mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-09 20:11:09 +00:00
Child trie api changes BREAKING (#4857)
Co-Authored-By: thiolliere <gui.thiolliere@gmail.com>
This commit is contained in:
@@ -26,7 +26,7 @@ use sp_state_machine::{
|
||||
ChangesTrieState, ChangesTrieStorage as StateChangesTrieStorage, ChangesTrieTransaction,
|
||||
StorageCollection, ChildStorageCollection,
|
||||
};
|
||||
use sp_storage::{StorageData, StorageKey, ChildInfo};
|
||||
use sp_storage::{StorageData, StorageKey, PrefixedStorageKey, ChildInfo};
|
||||
use crate::{
|
||||
blockchain::{
|
||||
Backend as BlockchainBackend, well_known_cache_keys
|
||||
@@ -280,6 +280,7 @@ impl<'a, State, Block> Iterator for KeyIterator<'a, State, Block> where
|
||||
Some(StorageKey(next_key))
|
||||
}
|
||||
}
|
||||
|
||||
/// Provides acess to storage primitives
|
||||
pub trait StorageProvider<Block: BlockT, B: Backend<Block>> {
|
||||
/// Given a `BlockId` and a key, return the value under the key in that block.
|
||||
@@ -310,8 +311,7 @@ pub trait StorageProvider<Block: BlockT, B: Backend<Block>> {
|
||||
fn child_storage(
|
||||
&self,
|
||||
id: &BlockId<Block>,
|
||||
storage_key: &StorageKey,
|
||||
child_info: ChildInfo,
|
||||
child_info: &ChildInfo,
|
||||
key: &StorageKey
|
||||
) -> sp_blockchain::Result<Option<StorageData>>;
|
||||
|
||||
@@ -319,8 +319,7 @@ pub trait StorageProvider<Block: BlockT, B: Backend<Block>> {
|
||||
fn child_storage_keys(
|
||||
&self,
|
||||
id: &BlockId<Block>,
|
||||
child_storage_key: &StorageKey,
|
||||
child_info: ChildInfo,
|
||||
child_info: &ChildInfo,
|
||||
key_prefix: &StorageKey
|
||||
) -> sp_blockchain::Result<Vec<StorageKey>>;
|
||||
|
||||
@@ -328,8 +327,7 @@ pub trait StorageProvider<Block: BlockT, B: Backend<Block>> {
|
||||
fn child_storage_hash(
|
||||
&self,
|
||||
id: &BlockId<Block>,
|
||||
storage_key: &StorageKey,
|
||||
child_info: ChildInfo,
|
||||
child_info: &ChildInfo,
|
||||
key: &StorageKey
|
||||
) -> sp_blockchain::Result<Option<Block::Hash>>;
|
||||
|
||||
@@ -351,7 +349,7 @@ pub trait StorageProvider<Block: BlockT, B: Backend<Block>> {
|
||||
&self,
|
||||
first: NumberFor<Block>,
|
||||
last: BlockId<Block>,
|
||||
storage_key: Option<&StorageKey>,
|
||||
storage_key: Option<&PrefixedStorageKey>,
|
||||
key: &StorageKey
|
||||
) -> sp_blockchain::Result<Vec<(NumberFor<Block>, u32)>>;
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ use sp_runtime::{
|
||||
},
|
||||
generic::BlockId
|
||||
};
|
||||
use sp_core::ChangesTrieConfigurationRange;
|
||||
use sp_core::{ChangesTrieConfigurationRange, storage::PrefixedStorageKey};
|
||||
use sp_state_machine::StorageProof;
|
||||
use sp_blockchain::{
|
||||
HeaderMetadata, well_known_cache_keys, HeaderBackend, Cache as BlockchainCache,
|
||||
@@ -81,12 +81,7 @@ pub struct RemoteReadChildRequest<Header: HeaderT> {
|
||||
/// Header of block at which read is performed.
|
||||
pub header: Header,
|
||||
/// Storage key for child.
|
||||
pub storage_key: Vec<u8>,
|
||||
/// Child trie source information.
|
||||
pub child_info: Vec<u8>,
|
||||
/// Child type, its required to resolve `child_info`
|
||||
/// content and choose child implementation.
|
||||
pub child_type: u32,
|
||||
pub storage_key: PrefixedStorageKey,
|
||||
/// Child storage key to read.
|
||||
pub keys: Vec<Vec<u8>>,
|
||||
/// Number of times to retry request. None means that default RETRY_COUNT is used.
|
||||
@@ -110,7 +105,7 @@ pub struct RemoteChangesRequest<Header: HeaderT> {
|
||||
/// Proofs for roots of ascendants of tries_roots.0 are provided by the remote node.
|
||||
pub tries_roots: (Header::Number, Header::Hash, Vec<Header::Hash>),
|
||||
/// Optional Child Storage key to read.
|
||||
pub storage_key: Option<Vec<u8>>,
|
||||
pub storage_key: Option<PrefixedStorageKey>,
|
||||
/// Storage key to read.
|
||||
pub key: Vec<u8>,
|
||||
/// Number of times to retry request. None means that default RETRY_COUNT is used.
|
||||
|
||||
@@ -19,7 +19,7 @@ use sp_runtime::{
|
||||
traits::{Block as BlockT},
|
||||
};
|
||||
use crate::{StorageProof, ChangesProof};
|
||||
use sp_storage::{ChildInfo, StorageKey};
|
||||
use sp_storage::{ChildInfo, StorageKey, PrefixedStorageKey};
|
||||
|
||||
/// Interface for providing block proving utilities.
|
||||
pub trait ProofProvider<Block: BlockT> {
|
||||
@@ -35,8 +35,7 @@ pub trait ProofProvider<Block: BlockT> {
|
||||
fn read_child_proof(
|
||||
&self,
|
||||
id: &BlockId<Block>,
|
||||
storage_key: &[u8],
|
||||
child_info: ChildInfo,
|
||||
child_info: &ChildInfo,
|
||||
keys: &mut dyn Iterator<Item=&[u8]>,
|
||||
) -> sp_blockchain::Result<StorageProof>;
|
||||
|
||||
@@ -65,7 +64,7 @@ pub trait ProofProvider<Block: BlockT> {
|
||||
last: Block::Hash,
|
||||
min: Block::Hash,
|
||||
max: Block::Hash,
|
||||
storage_key: Option<&StorageKey>,
|
||||
storage_key: Option<&PrefixedStorageKey>,
|
||||
key: &StorageKey,
|
||||
) -> sp_blockchain::Result<ChangesProof<Block::Header>>;
|
||||
}
|
||||
|
||||
@@ -74,17 +74,14 @@ impl<G: RuntimeGenesis, E> BuildStorage for ChainSpec<G, E> {
|
||||
fn build_storage(&self) -> Result<Storage, String> {
|
||||
match self.genesis.resolve()? {
|
||||
Genesis::Runtime(gc) => gc.build_storage(),
|
||||
Genesis::Raw(RawGenesis { top: map, children: children_map }) => Ok(Storage {
|
||||
Genesis::Raw(RawGenesis { top: map, children_default: children_map }) => Ok(Storage {
|
||||
top: map.into_iter().map(|(k, v)| (k.0, v.0)).collect(),
|
||||
children: children_map.into_iter().map(|(sk, child_content)| {
|
||||
let child_info = ChildInfo::resolve_child_info(
|
||||
child_content.child_type,
|
||||
child_content.child_info.as_slice(),
|
||||
).expect("chain spec contains correct content").to_owned();
|
||||
children_default: children_map.into_iter().map(|(storage_key, child_content)| {
|
||||
let child_info = ChildInfo::new_default(storage_key.0.as_slice());
|
||||
(
|
||||
sk.0,
|
||||
storage_key.0,
|
||||
StorageChild {
|
||||
data: child_content.data.into_iter().map(|(k, v)| (k.0, v.0)).collect(),
|
||||
data: child_content.into_iter().map(|(k, v)| (k.0, v.0)).collect(),
|
||||
child_info,
|
||||
},
|
||||
)
|
||||
@@ -103,22 +100,13 @@ impl<G: RuntimeGenesis, E> BuildStorage for ChainSpec<G, E> {
|
||||
|
||||
type GenesisStorage = HashMap<StorageKey, StorageData>;
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[serde(deny_unknown_fields)]
|
||||
struct ChildRawStorage {
|
||||
data: GenesisStorage,
|
||||
child_info: Vec<u8>,
|
||||
child_type: u32,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[serde(deny_unknown_fields)]
|
||||
/// Storage content for genesis block.
|
||||
struct RawGenesis {
|
||||
top: GenesisStorage,
|
||||
children: HashMap<StorageKey, ChildRawStorage>,
|
||||
children_default: HashMap<StorageKey, GenesisStorage>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
@@ -291,23 +279,16 @@ impl<G: RuntimeGenesis, E: serde::Serialize + Clone> ChainSpec<G, E> {
|
||||
let top = storage.top.into_iter()
|
||||
.map(|(k, v)| (StorageKey(k), StorageData(v)))
|
||||
.collect();
|
||||
let children = storage.children.into_iter()
|
||||
.map(|(sk, child)| {
|
||||
let info = child.child_info.as_ref();
|
||||
let (info, ci_type) = info.info();
|
||||
(
|
||||
StorageKey(sk),
|
||||
ChildRawStorage {
|
||||
data: child.data.into_iter()
|
||||
.map(|(k, v)| (StorageKey(k), StorageData(v)))
|
||||
.collect(),
|
||||
child_info: info.to_vec(),
|
||||
child_type: ci_type,
|
||||
},
|
||||
)})
|
||||
let children_default = storage.children_default.into_iter()
|
||||
.map(|(sk, child)| (
|
||||
StorageKey(sk),
|
||||
child.data.into_iter()
|
||||
.map(|(k, v)| (StorageKey(k), StorageData(v)))
|
||||
.collect(),
|
||||
))
|
||||
.collect();
|
||||
|
||||
Genesis::Raw(RawGenesis { top, children })
|
||||
Genesis::Raw(RawGenesis { top, children_default })
|
||||
},
|
||||
(_, genesis) => genesis,
|
||||
};
|
||||
|
||||
@@ -77,10 +77,9 @@ impl<B: BlockT> BenchmarkingState<B> {
|
||||
};
|
||||
|
||||
state.reopen()?;
|
||||
let child_delta = genesis.children.into_iter().map(|(storage_key, child_content)| (
|
||||
storage_key,
|
||||
let child_delta = genesis.children_default.into_iter().map(|(_storage_key, child_content)| (
|
||||
child_content.child_info,
|
||||
child_content.data.into_iter().map(|(k, v)| (k, Some(v))),
|
||||
child_content.child_info
|
||||
));
|
||||
let (root, transaction): (B::Hash, _) = state.state.borrow_mut().as_mut().unwrap().full_storage_root(
|
||||
genesis.top.into_iter().map(|(k, v)| (k, Some(v))),
|
||||
@@ -129,11 +128,10 @@ impl<B: BlockT> StateBackend<HashFor<B>> for BenchmarkingState<B> {
|
||||
|
||||
fn child_storage(
|
||||
&self,
|
||||
storage_key: &[u8],
|
||||
child_info: ChildInfo,
|
||||
child_info: &ChildInfo,
|
||||
key: &[u8],
|
||||
) -> Result<Option<Vec<u8>>, Self::Error> {
|
||||
self.state.borrow().as_ref().ok_or_else(state_err)?.child_storage(storage_key, child_info, key)
|
||||
self.state.borrow().as_ref().ok_or_else(state_err)?.child_storage(child_info, key)
|
||||
}
|
||||
|
||||
fn exists_storage(&self, key: &[u8]) -> Result<bool, Self::Error> {
|
||||
@@ -142,11 +140,10 @@ impl<B: BlockT> StateBackend<HashFor<B>> for BenchmarkingState<B> {
|
||||
|
||||
fn exists_child_storage(
|
||||
&self,
|
||||
storage_key: &[u8],
|
||||
child_info: ChildInfo,
|
||||
child_info: &ChildInfo,
|
||||
key: &[u8],
|
||||
) -> Result<bool, Self::Error> {
|
||||
self.state.borrow().as_ref().ok_or_else(state_err)?.exists_child_storage(storage_key, child_info, key)
|
||||
self.state.borrow().as_ref().ok_or_else(state_err)?.exists_child_storage(child_info, key)
|
||||
}
|
||||
|
||||
fn next_storage_key(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error> {
|
||||
@@ -155,11 +152,10 @@ impl<B: BlockT> StateBackend<HashFor<B>> for BenchmarkingState<B> {
|
||||
|
||||
fn next_child_storage_key(
|
||||
&self,
|
||||
storage_key: &[u8],
|
||||
child_info: ChildInfo,
|
||||
child_info: &ChildInfo,
|
||||
key: &[u8],
|
||||
) -> Result<Option<Vec<u8>>, Self::Error> {
|
||||
self.state.borrow().as_ref().ok_or_else(state_err)?.next_child_storage_key(storage_key, child_info, key)
|
||||
self.state.borrow().as_ref().ok_or_else(state_err)?.next_child_storage_key(child_info, key)
|
||||
}
|
||||
|
||||
fn for_keys_with_prefix<F: FnMut(&[u8])>(&self, prefix: &[u8], f: F) {
|
||||
@@ -176,24 +172,22 @@ impl<B: BlockT> StateBackend<HashFor<B>> for BenchmarkingState<B> {
|
||||
|
||||
fn for_keys_in_child_storage<F: FnMut(&[u8])>(
|
||||
&self,
|
||||
storage_key: &[u8],
|
||||
child_info: ChildInfo,
|
||||
child_info: &ChildInfo,
|
||||
f: F,
|
||||
) {
|
||||
if let Some(ref state) = *self.state.borrow() {
|
||||
state.for_keys_in_child_storage(storage_key, child_info, f)
|
||||
state.for_keys_in_child_storage(child_info, f)
|
||||
}
|
||||
}
|
||||
|
||||
fn for_child_keys_with_prefix<F: FnMut(&[u8])>(
|
||||
&self,
|
||||
storage_key: &[u8],
|
||||
child_info: ChildInfo,
|
||||
child_info: &ChildInfo,
|
||||
prefix: &[u8],
|
||||
f: F,
|
||||
) {
|
||||
if let Some(ref state) = *self.state.borrow() {
|
||||
state.for_child_keys_with_prefix(storage_key, child_info, prefix, f)
|
||||
state.for_child_keys_with_prefix(child_info, prefix, f)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,13 +199,12 @@ impl<B: BlockT> StateBackend<HashFor<B>> for BenchmarkingState<B> {
|
||||
|
||||
fn child_storage_root<I>(
|
||||
&self,
|
||||
storage_key: &[u8],
|
||||
child_info: ChildInfo,
|
||||
child_info: &ChildInfo,
|
||||
delta: I,
|
||||
) -> (B::Hash, bool, Self::Transaction) where
|
||||
I: IntoIterator<Item=(Vec<u8>, Option<Vec<u8>>)>,
|
||||
{
|
||||
self.state.borrow().as_ref().map_or(Default::default(), |s| s.child_storage_root(storage_key, child_info, delta))
|
||||
self.state.borrow().as_ref().map_or(Default::default(), |s| s.child_storage_root(child_info, delta))
|
||||
}
|
||||
|
||||
fn pairs(&self) -> Vec<(Vec<u8>, Vec<u8>)> {
|
||||
@@ -224,11 +217,10 @@ impl<B: BlockT> StateBackend<HashFor<B>> for BenchmarkingState<B> {
|
||||
|
||||
fn child_keys(
|
||||
&self,
|
||||
storage_key: &[u8],
|
||||
child_info: ChildInfo,
|
||||
child_info: &ChildInfo,
|
||||
prefix: &[u8],
|
||||
) -> Vec<Vec<u8>> {
|
||||
self.state.borrow().as_ref().map_or(Default::default(), |s| s.child_keys(storage_key, child_info, prefix))
|
||||
self.state.borrow().as_ref().map_or(Default::default(), |s| s.child_keys(child_info, prefix))
|
||||
}
|
||||
|
||||
fn as_trie_backend(&mut self)
|
||||
|
||||
@@ -26,6 +26,7 @@ use sp_trie::MemoryDB;
|
||||
use sc_client_api::backend::PrunableStateChangesTrieStorage;
|
||||
use sp_blockchain::{well_known_cache_keys, Cache as BlockchainCache};
|
||||
use sp_core::{ChangesTrieConfiguration, ChangesTrieConfigurationRange, convert_hash};
|
||||
use sp_core::storage::PrefixedStorageKey;
|
||||
use sp_database::Transaction;
|
||||
use sp_runtime::traits::{
|
||||
Block as BlockT, Header as HeaderT, HashFor, NumberFor, One, Zero, CheckedSub,
|
||||
@@ -482,7 +483,7 @@ where
|
||||
fn with_cached_changed_keys(
|
||||
&self,
|
||||
root: &Block::Hash,
|
||||
functor: &mut dyn FnMut(&HashMap<Option<Vec<u8>>, HashSet<Vec<u8>>>),
|
||||
functor: &mut dyn FnMut(&HashMap<Option<PrefixedStorageKey>, HashSet<Vec<u8>>>),
|
||||
) -> bool {
|
||||
self.build_cache.read().with_changed_keys(root, functor)
|
||||
}
|
||||
|
||||
@@ -159,11 +159,10 @@ impl<B: BlockT> StateBackend<HashFor<B>> for RefTrackingState<B> {
|
||||
|
||||
fn child_storage(
|
||||
&self,
|
||||
storage_key: &[u8],
|
||||
child_info: ChildInfo,
|
||||
child_info: &ChildInfo,
|
||||
key: &[u8],
|
||||
) -> Result<Option<Vec<u8>>, Self::Error> {
|
||||
self.state.child_storage(storage_key, child_info, key)
|
||||
self.state.child_storage(child_info, key)
|
||||
}
|
||||
|
||||
fn exists_storage(&self, key: &[u8]) -> Result<bool, Self::Error> {
|
||||
@@ -172,11 +171,10 @@ impl<B: BlockT> StateBackend<HashFor<B>> for RefTrackingState<B> {
|
||||
|
||||
fn exists_child_storage(
|
||||
&self,
|
||||
storage_key: &[u8],
|
||||
child_info: ChildInfo,
|
||||
child_info: &ChildInfo,
|
||||
key: &[u8],
|
||||
) -> Result<bool, Self::Error> {
|
||||
self.state.exists_child_storage(storage_key, child_info, key)
|
||||
self.state.exists_child_storage(child_info, key)
|
||||
}
|
||||
|
||||
fn next_storage_key(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error> {
|
||||
@@ -185,11 +183,10 @@ impl<B: BlockT> StateBackend<HashFor<B>> for RefTrackingState<B> {
|
||||
|
||||
fn next_child_storage_key(
|
||||
&self,
|
||||
storage_key: &[u8],
|
||||
child_info: ChildInfo,
|
||||
child_info: &ChildInfo,
|
||||
key: &[u8],
|
||||
) -> Result<Option<Vec<u8>>, Self::Error> {
|
||||
self.state.next_child_storage_key(storage_key, child_info, key)
|
||||
self.state.next_child_storage_key(child_info, key)
|
||||
}
|
||||
|
||||
fn for_keys_with_prefix<F: FnMut(&[u8])>(&self, prefix: &[u8], f: F) {
|
||||
@@ -202,21 +199,19 @@ impl<B: BlockT> StateBackend<HashFor<B>> for RefTrackingState<B> {
|
||||
|
||||
fn for_keys_in_child_storage<F: FnMut(&[u8])>(
|
||||
&self,
|
||||
storage_key: &[u8],
|
||||
child_info: ChildInfo,
|
||||
child_info: &ChildInfo,
|
||||
f: F,
|
||||
) {
|
||||
self.state.for_keys_in_child_storage(storage_key, child_info, f)
|
||||
self.state.for_keys_in_child_storage(child_info, f)
|
||||
}
|
||||
|
||||
fn for_child_keys_with_prefix<F: FnMut(&[u8])>(
|
||||
&self,
|
||||
storage_key: &[u8],
|
||||
child_info: ChildInfo,
|
||||
child_info: &ChildInfo,
|
||||
prefix: &[u8],
|
||||
f: F,
|
||||
) {
|
||||
self.state.for_child_keys_with_prefix(storage_key, child_info, prefix, f)
|
||||
self.state.for_child_keys_with_prefix(child_info, prefix, f)
|
||||
}
|
||||
|
||||
fn storage_root<I>(&self, delta: I) -> (B::Hash, Self::Transaction)
|
||||
@@ -228,14 +223,13 @@ impl<B: BlockT> StateBackend<HashFor<B>> for RefTrackingState<B> {
|
||||
|
||||
fn child_storage_root<I>(
|
||||
&self,
|
||||
storage_key: &[u8],
|
||||
child_info: ChildInfo,
|
||||
child_info: &ChildInfo,
|
||||
delta: I,
|
||||
) -> (B::Hash, bool, Self::Transaction)
|
||||
where
|
||||
I: IntoIterator<Item=(Vec<u8>, Option<Vec<u8>>)>,
|
||||
{
|
||||
self.state.child_storage_root(storage_key, child_info, delta)
|
||||
self.state.child_storage_root(child_info, delta)
|
||||
}
|
||||
|
||||
fn pairs(&self) -> Vec<(Vec<u8>, Vec<u8>)> {
|
||||
@@ -248,11 +242,10 @@ impl<B: BlockT> StateBackend<HashFor<B>> for RefTrackingState<B> {
|
||||
|
||||
fn child_keys(
|
||||
&self,
|
||||
storage_key: &[u8],
|
||||
child_info: ChildInfo,
|
||||
child_info: &ChildInfo,
|
||||
prefix: &[u8],
|
||||
) -> Vec<Vec<u8>> {
|
||||
self.state.child_keys(storage_key, child_info, prefix)
|
||||
self.state.child_keys(child_info, prefix)
|
||||
}
|
||||
|
||||
fn as_trie_backend(&mut self)
|
||||
@@ -631,16 +624,10 @@ impl<Block: BlockT> sc_client_api::backend::BlockImportOperation<Block> for Bloc
|
||||
return Err(sp_blockchain::Error::GenesisInvalid.into());
|
||||
}
|
||||
|
||||
for child_key in storage.children.keys() {
|
||||
if !well_known_keys::is_child_storage_key(&child_key) {
|
||||
return Err(sp_blockchain::Error::GenesisInvalid.into());
|
||||
}
|
||||
}
|
||||
|
||||
let child_delta = storage.children.into_iter().map(|(storage_key, child_content)| (
|
||||
storage_key,
|
||||
child_content.data.into_iter().map(|(k, v)| (k, Some(v))), child_content.child_info),
|
||||
);
|
||||
let child_delta = storage.children_default.into_iter().map(|(_storage_key, child_content)|(
|
||||
child_content.child_info,
|
||||
child_content.data.into_iter().map(|(k, v)| (k, Some(v))),
|
||||
));
|
||||
|
||||
let mut changes_trie_config: Option<ChangesTrieConfiguration> = None;
|
||||
let (root, transaction) = self.old_state.full_storage_root(
|
||||
@@ -1808,7 +1795,7 @@ pub(crate) mod tests {
|
||||
|
||||
op.reset_storage(Storage {
|
||||
top: storage.iter().cloned().collect(),
|
||||
children: Default::default(),
|
||||
children_default: Default::default(),
|
||||
}).unwrap();
|
||||
op.set_block_data(
|
||||
header.clone(),
|
||||
@@ -1894,7 +1881,7 @@ pub(crate) mod tests {
|
||||
|
||||
op.reset_storage(Storage {
|
||||
top: storage.iter().cloned().collect(),
|
||||
children: Default::default(),
|
||||
children_default: Default::default(),
|
||||
}).unwrap();
|
||||
|
||||
key = op.db_updates.insert(EMPTY_PREFIX, b"hello");
|
||||
|
||||
@@ -542,11 +542,10 @@ impl<S: StateBackend<HashFor<B>>, B: BlockT> StateBackend<HashFor<B>> for Cachin
|
||||
|
||||
fn child_storage(
|
||||
&self,
|
||||
storage_key: &[u8],
|
||||
child_info: ChildInfo,
|
||||
child_info: &ChildInfo,
|
||||
key: &[u8],
|
||||
) -> Result<Option<Vec<u8>>, Self::Error> {
|
||||
let key = (storage_key.to_vec(), key.to_vec());
|
||||
let key = (child_info.storage_key().to_vec(), key.to_vec());
|
||||
let local_cache = self.cache.local_cache.upgradable_read();
|
||||
if let Some(entry) = local_cache.child_storage.get(&key).cloned() {
|
||||
trace!("Found in local cache: {:?}", key);
|
||||
@@ -564,7 +563,7 @@ impl<S: StateBackend<HashFor<B>>, B: BlockT> StateBackend<HashFor<B>> for Cachin
|
||||
}
|
||||
}
|
||||
trace!("Cache miss: {:?}", key);
|
||||
let value = self.state.child_storage(storage_key, child_info, &key.1[..])?;
|
||||
let value = self.state.child_storage(child_info, &key.1[..])?;
|
||||
|
||||
// just pass it through the usage counter
|
||||
let value = self.usage.tally_child_key_read(&key, value, false);
|
||||
@@ -579,20 +578,18 @@ impl<S: StateBackend<HashFor<B>>, B: BlockT> StateBackend<HashFor<B>> for Cachin
|
||||
|
||||
fn exists_child_storage(
|
||||
&self,
|
||||
storage_key: &[u8],
|
||||
child_info: ChildInfo,
|
||||
child_info: &ChildInfo,
|
||||
key: &[u8],
|
||||
) -> Result<bool, Self::Error> {
|
||||
self.state.exists_child_storage(storage_key, child_info, key)
|
||||
self.state.exists_child_storage(child_info, key)
|
||||
}
|
||||
|
||||
fn for_keys_in_child_storage<F: FnMut(&[u8])>(
|
||||
&self,
|
||||
storage_key: &[u8],
|
||||
child_info: ChildInfo,
|
||||
child_info: &ChildInfo,
|
||||
f: F,
|
||||
) {
|
||||
self.state.for_keys_in_child_storage(storage_key, child_info, f)
|
||||
self.state.for_keys_in_child_storage(child_info, f)
|
||||
}
|
||||
|
||||
fn next_storage_key(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error> {
|
||||
@@ -601,11 +598,10 @@ impl<S: StateBackend<HashFor<B>>, B: BlockT> StateBackend<HashFor<B>> for Cachin
|
||||
|
||||
fn next_child_storage_key(
|
||||
&self,
|
||||
storage_key: &[u8],
|
||||
child_info: ChildInfo,
|
||||
child_info: &ChildInfo,
|
||||
key: &[u8],
|
||||
) -> Result<Option<Vec<u8>>, Self::Error> {
|
||||
self.state.next_child_storage_key(storage_key, child_info, key)
|
||||
self.state.next_child_storage_key(child_info, key)
|
||||
}
|
||||
|
||||
fn for_keys_with_prefix<F: FnMut(&[u8])>(&self, prefix: &[u8], f: F) {
|
||||
@@ -618,12 +614,11 @@ impl<S: StateBackend<HashFor<B>>, B: BlockT> StateBackend<HashFor<B>> for Cachin
|
||||
|
||||
fn for_child_keys_with_prefix<F: FnMut(&[u8])>(
|
||||
&self,
|
||||
storage_key: &[u8],
|
||||
child_info: ChildInfo,
|
||||
child_info: &ChildInfo,
|
||||
prefix: &[u8],
|
||||
f: F,
|
||||
) {
|
||||
self.state.for_child_keys_with_prefix(storage_key, child_info, prefix, f)
|
||||
self.state.for_child_keys_with_prefix(child_info, prefix, f)
|
||||
}
|
||||
|
||||
fn storage_root<I>(&self, delta: I) -> (B::Hash, Self::Transaction)
|
||||
@@ -635,14 +630,13 @@ impl<S: StateBackend<HashFor<B>>, B: BlockT> StateBackend<HashFor<B>> for Cachin
|
||||
|
||||
fn child_storage_root<I>(
|
||||
&self,
|
||||
storage_key: &[u8],
|
||||
child_info: ChildInfo,
|
||||
child_info: &ChildInfo,
|
||||
delta: I,
|
||||
) -> (B::Hash, bool, Self::Transaction)
|
||||
where
|
||||
I: IntoIterator<Item=(Vec<u8>, Option<Vec<u8>>)>,
|
||||
{
|
||||
self.state.child_storage_root(storage_key, child_info, delta)
|
||||
self.state.child_storage_root(child_info, delta)
|
||||
}
|
||||
|
||||
fn pairs(&self) -> Vec<(Vec<u8>, Vec<u8>)> {
|
||||
@@ -655,11 +649,10 @@ impl<S: StateBackend<HashFor<B>>, B: BlockT> StateBackend<HashFor<B>> for Cachin
|
||||
|
||||
fn child_keys(
|
||||
&self,
|
||||
storage_key: &[u8],
|
||||
child_info: ChildInfo,
|
||||
child_info: &ChildInfo,
|
||||
prefix: &[u8],
|
||||
) -> Vec<Vec<u8>> {
|
||||
self.state.child_keys(storage_key, child_info, prefix)
|
||||
self.state.child_keys(child_info, prefix)
|
||||
}
|
||||
|
||||
fn as_trie_backend(&mut self) -> Option<&TrieBackend<Self::TrieBackendStorage, HashFor<B>>> {
|
||||
@@ -758,11 +751,10 @@ impl<S: StateBackend<HashFor<B>>, B: BlockT> StateBackend<HashFor<B>> for Syncin
|
||||
|
||||
fn child_storage(
|
||||
&self,
|
||||
storage_key: &[u8],
|
||||
child_info: ChildInfo,
|
||||
child_info: &ChildInfo,
|
||||
key: &[u8],
|
||||
) -> Result<Option<Vec<u8>>, Self::Error> {
|
||||
self.caching_state().child_storage(storage_key, child_info, key)
|
||||
self.caching_state().child_storage(child_info, key)
|
||||
}
|
||||
|
||||
fn exists_storage(&self, key: &[u8]) -> Result<bool, Self::Error> {
|
||||
@@ -771,20 +763,18 @@ impl<S: StateBackend<HashFor<B>>, B: BlockT> StateBackend<HashFor<B>> for Syncin
|
||||
|
||||
fn exists_child_storage(
|
||||
&self,
|
||||
storage_key: &[u8],
|
||||
child_info: ChildInfo,
|
||||
child_info: &ChildInfo,
|
||||
key: &[u8],
|
||||
) -> Result<bool, Self::Error> {
|
||||
self.caching_state().exists_child_storage(storage_key, child_info, key)
|
||||
self.caching_state().exists_child_storage(child_info, key)
|
||||
}
|
||||
|
||||
fn for_keys_in_child_storage<F: FnMut(&[u8])>(
|
||||
&self,
|
||||
storage_key: &[u8],
|
||||
child_info: ChildInfo,
|
||||
child_info: &ChildInfo,
|
||||
f: F,
|
||||
) {
|
||||
self.caching_state().for_keys_in_child_storage(storage_key, child_info, f)
|
||||
self.caching_state().for_keys_in_child_storage(child_info, f)
|
||||
}
|
||||
|
||||
fn next_storage_key(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error> {
|
||||
@@ -793,11 +783,10 @@ impl<S: StateBackend<HashFor<B>>, B: BlockT> StateBackend<HashFor<B>> for Syncin
|
||||
|
||||
fn next_child_storage_key(
|
||||
&self,
|
||||
storage_key: &[u8],
|
||||
child_info: ChildInfo,
|
||||
child_info: &ChildInfo,
|
||||
key: &[u8],
|
||||
) -> Result<Option<Vec<u8>>, Self::Error> {
|
||||
self.caching_state().next_child_storage_key(storage_key, child_info, key)
|
||||
self.caching_state().next_child_storage_key(child_info, key)
|
||||
}
|
||||
|
||||
fn for_keys_with_prefix<F: FnMut(&[u8])>(&self, prefix: &[u8], f: F) {
|
||||
@@ -810,12 +799,11 @@ impl<S: StateBackend<HashFor<B>>, B: BlockT> StateBackend<HashFor<B>> for Syncin
|
||||
|
||||
fn for_child_keys_with_prefix<F: FnMut(&[u8])>(
|
||||
&self,
|
||||
storage_key: &[u8],
|
||||
child_info: ChildInfo,
|
||||
child_info: &ChildInfo,
|
||||
prefix: &[u8],
|
||||
f: F,
|
||||
) {
|
||||
self.caching_state().for_child_keys_with_prefix(storage_key, child_info, prefix, f)
|
||||
self.caching_state().for_child_keys_with_prefix(child_info, prefix, f)
|
||||
}
|
||||
|
||||
fn storage_root<I>(&self, delta: I) -> (B::Hash, Self::Transaction)
|
||||
@@ -827,14 +815,13 @@ impl<S: StateBackend<HashFor<B>>, B: BlockT> StateBackend<HashFor<B>> for Syncin
|
||||
|
||||
fn child_storage_root<I>(
|
||||
&self,
|
||||
storage_key: &[u8],
|
||||
child_info: ChildInfo,
|
||||
child_info: &ChildInfo,
|
||||
delta: I,
|
||||
) -> (B::Hash, bool, Self::Transaction)
|
||||
where
|
||||
I: IntoIterator<Item=(Vec<u8>, Option<Vec<u8>>)>,
|
||||
{
|
||||
self.caching_state().child_storage_root(storage_key, child_info, delta)
|
||||
self.caching_state().child_storage_root(child_info, delta)
|
||||
}
|
||||
|
||||
fn pairs(&self) -> Vec<(Vec<u8>, Vec<u8>)> {
|
||||
@@ -847,11 +834,10 @@ impl<S: StateBackend<HashFor<B>>, B: BlockT> StateBackend<HashFor<B>> for Syncin
|
||||
|
||||
fn child_keys(
|
||||
&self,
|
||||
storage_key: &[u8],
|
||||
child_info: ChildInfo,
|
||||
child_info: &ChildInfo,
|
||||
prefix: &[u8],
|
||||
) -> Vec<Vec<u8>> {
|
||||
self.caching_state().child_keys(storage_key, child_info, prefix)
|
||||
self.caching_state().child_keys(child_info, prefix)
|
||||
}
|
||||
|
||||
fn as_trie_backend(&mut self) -> Option<&TrieBackend<Self::TrieBackendStorage, HashFor<B>>> {
|
||||
|
||||
@@ -186,7 +186,7 @@ fn storage_should_work(wasm_method: WasmExecutionMethod) {
|
||||
b"foo".to_vec() => b"bar".to_vec(),
|
||||
b"baz".to_vec() => b"bar".to_vec()
|
||||
],
|
||||
children: map![],
|
||||
children_default: map![],
|
||||
});
|
||||
assert_eq!(ext, expected);
|
||||
}
|
||||
@@ -220,7 +220,7 @@ fn clear_prefix_should_work(wasm_method: WasmExecutionMethod) {
|
||||
b"aab".to_vec() => b"2".to_vec(),
|
||||
b"bbb".to_vec() => b"5".to_vec()
|
||||
],
|
||||
children: map![],
|
||||
children_default: map![],
|
||||
});
|
||||
assert_eq!(expected, ext);
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ use libp2p::core::{ConnectedPoint, connection::{ConnectionId, ListenerId}};
|
||||
use libp2p::swarm::{ProtocolsHandler, IntoProtocolsHandler};
|
||||
use libp2p::swarm::{NetworkBehaviour, NetworkBehaviourAction, PollParameters};
|
||||
use sp_core::{
|
||||
storage::{StorageKey, ChildInfo},
|
||||
storage::{StorageKey, PrefixedStorageKey, ChildInfo, ChildType},
|
||||
hexdisplay::HexDisplay
|
||||
};
|
||||
use sp_consensus::{
|
||||
@@ -1522,37 +1522,28 @@ impl<B: BlockT, H: ExHashT> Protocol<B, H> {
|
||||
|
||||
trace!(target: "sync", "Remote read child request {} from {} ({} {} at {})",
|
||||
request.id, who, HexDisplay::from(&request.storage_key), keys_str(), request.block);
|
||||
let proof = if let Some(child_info) = ChildInfo::resolve_child_info(request.child_type, &request.child_info[..]) {
|
||||
match self.context_data.chain.read_child_proof(
|
||||
&BlockId::Hash(request.block),
|
||||
&request.storage_key,
|
||||
child_info,
|
||||
&mut request.keys.iter().map(AsRef::as_ref),
|
||||
) {
|
||||
Ok(proof) => proof,
|
||||
Err(error) => {
|
||||
trace!(target: "sync", "Remote read child request {} from {} ({} {} at {}) failed with: {}",
|
||||
request.id,
|
||||
who,
|
||||
HexDisplay::from(&request.storage_key),
|
||||
keys_str(),
|
||||
request.block,
|
||||
error
|
||||
);
|
||||
StorageProof::empty()
|
||||
}
|
||||
let prefixed_key = PrefixedStorageKey::new_ref(&request.storage_key);
|
||||
let child_info = match ChildType::from_prefixed_key(prefixed_key) {
|
||||
Some((ChildType::ParentKeyId, storage_key)) => Ok(ChildInfo::new_default(storage_key)),
|
||||
None => Err("Invalid child storage key".into()),
|
||||
};
|
||||
let proof = match child_info.and_then(|child_info| self.context_data.chain.read_child_proof(
|
||||
&BlockId::Hash(request.block),
|
||||
&child_info,
|
||||
&mut request.keys.iter().map(AsRef::as_ref),
|
||||
)) {
|
||||
Ok(proof) => proof,
|
||||
Err(error) => {
|
||||
trace!(target: "sync", "Remote read child request {} from {} ({} {} at {}) failed with: {}",
|
||||
request.id,
|
||||
who,
|
||||
HexDisplay::from(&request.storage_key),
|
||||
keys_str(),
|
||||
request.block,
|
||||
error
|
||||
);
|
||||
StorageProof::empty()
|
||||
}
|
||||
} else {
|
||||
trace!(target: "sync", "Remote read child request {} from {} ({} {} at {}) failed with: {}",
|
||||
request.id,
|
||||
who,
|
||||
HexDisplay::from(&request.storage_key),
|
||||
keys_str(),
|
||||
request.block,
|
||||
"invalid child info and type",
|
||||
);
|
||||
|
||||
StorageProof::empty()
|
||||
};
|
||||
self.send_message(
|
||||
&who,
|
||||
@@ -1610,14 +1601,16 @@ impl<B: BlockT, H: ExHashT> Protocol<B, H> {
|
||||
request.first,
|
||||
request.last
|
||||
);
|
||||
let storage_key = request.storage_key.map(|sk| StorageKey(sk));
|
||||
let key = StorageKey(request.key);
|
||||
let prefixed_key = request.storage_key.as_ref()
|
||||
.map(|storage_key| PrefixedStorageKey::new_ref(storage_key));
|
||||
let (first, last, min, max) = (request.first, request.last, request.min, request.max);
|
||||
let proof = match self.context_data.chain.key_changes_proof(
|
||||
request.first,
|
||||
request.last,
|
||||
request.min,
|
||||
request.max,
|
||||
storage_key.as_ref(),
|
||||
first,
|
||||
last,
|
||||
min,
|
||||
max,
|
||||
prefixed_key,
|
||||
&key,
|
||||
) {
|
||||
Ok(proof) => proof,
|
||||
@@ -1625,8 +1618,8 @@ impl<B: BlockT, H: ExHashT> Protocol<B, H> {
|
||||
trace!(target: "sync", "Remote changes proof request {} from {} for key {} ({}..{}) failed with: {}",
|
||||
request.id,
|
||||
who,
|
||||
if let Some(sk) = storage_key {
|
||||
format!("{} : {}", HexDisplay::from(&sk.0), HexDisplay::from(&key.0))
|
||||
if let Some(sk) = request.storage_key.as_ref() {
|
||||
format!("{} : {}", HexDisplay::from(sk), HexDisplay::from(&key.0))
|
||||
} else {
|
||||
HexDisplay::from(&key.0).to_string()
|
||||
},
|
||||
|
||||
@@ -58,7 +58,7 @@ use sc_client::light::fetcher;
|
||||
use sc_client_api::StorageProof;
|
||||
use sc_peerset::ReputationChange;
|
||||
use sp_core::{
|
||||
storage::{ChildInfo, StorageKey},
|
||||
storage::{ChildInfo, ChildType,StorageKey, PrefixedStorageKey},
|
||||
hexdisplay::HexDisplay,
|
||||
};
|
||||
use smallvec::SmallVec;
|
||||
@@ -617,35 +617,27 @@ where
|
||||
|
||||
let block = Decode::decode(&mut request.block.as_ref())?;
|
||||
|
||||
let proof =
|
||||
if let Some(info) = ChildInfo::resolve_child_info(request.child_type, &request.child_info[..]) {
|
||||
match self.chain.read_child_proof(
|
||||
&BlockId::Hash(block),
|
||||
&request.storage_key,
|
||||
info,
|
||||
&mut request.keys.iter().map(AsRef::as_ref)
|
||||
) {
|
||||
Ok(proof) => proof,
|
||||
Err(error) => {
|
||||
log::trace!("remote read child request from {} ({} {} at {:?}) failed with: {}",
|
||||
peer,
|
||||
HexDisplay::from(&request.storage_key),
|
||||
fmt_keys(request.keys.first(), request.keys.last()),
|
||||
request.block,
|
||||
error);
|
||||
StorageProof::empty()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let prefixed_key = PrefixedStorageKey::new_ref(&request.storage_key);
|
||||
let child_info = match ChildType::from_prefixed_key(prefixed_key) {
|
||||
Some((ChildType::ParentKeyId, storage_key)) => Ok(ChildInfo::new_default(storage_key)),
|
||||
None => Err("Invalid child storage key".into()),
|
||||
};
|
||||
let proof = match child_info.and_then(|child_info| self.chain.read_child_proof(
|
||||
&BlockId::Hash(block),
|
||||
&child_info,
|
||||
&mut request.keys.iter().map(AsRef::as_ref)
|
||||
)) {
|
||||
Ok(proof) => proof,
|
||||
Err(error) => {
|
||||
log::trace!("remote read child request from {} ({} {} at {:?}) failed with: {}",
|
||||
peer,
|
||||
HexDisplay::from(&request.storage_key),
|
||||
fmt_keys(request.keys.first(), request.keys.last()),
|
||||
request.block,
|
||||
"invalid child info and type"
|
||||
);
|
||||
error);
|
||||
StorageProof::empty()
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
let response = {
|
||||
let r = api::v1::light::RemoteReadResponse { proof: proof.encode() };
|
||||
@@ -704,23 +696,18 @@ where
|
||||
let min = Decode::decode(&mut request.min.as_ref())?;
|
||||
let max = Decode::decode(&mut request.max.as_ref())?;
|
||||
let key = StorageKey(request.key.clone());
|
||||
let storage_key =
|
||||
if request.storage_key.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(StorageKey(request.storage_key.clone()))
|
||||
};
|
||||
let storage_key = if request.storage_key.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(PrefixedStorageKey::new_ref(&request.storage_key))
|
||||
};
|
||||
|
||||
let proof = match self.chain.key_changes_proof(first, last, min, max, storage_key.as_ref(), &key) {
|
||||
let proof = match self.chain.key_changes_proof(first, last, min, max, storage_key, &key) {
|
||||
Ok(proof) => proof,
|
||||
Err(error) => {
|
||||
log::trace!("remote changes proof request from {} for key {} ({:?}..{:?}) failed with: {}",
|
||||
peer,
|
||||
if let Some(sk) = storage_key {
|
||||
format!("{} : {}", HexDisplay::from(&sk.0), HexDisplay::from(&key.0))
|
||||
} else {
|
||||
HexDisplay::from(&key.0).to_string()
|
||||
},
|
||||
format!("{} : {}", HexDisplay::from(&request.storage_key), HexDisplay::from(&key.0)),
|
||||
request.first,
|
||||
request.last,
|
||||
error);
|
||||
@@ -1092,9 +1079,7 @@ fn serialize_request<B: Block>(request: &Request<B>) -> Result<Vec<u8>, prost::E
|
||||
Request::ReadChild { request, .. } => {
|
||||
let r = api::v1::light::RemoteReadChildRequest {
|
||||
block: request.block.encode(),
|
||||
storage_key: request.storage_key.clone(),
|
||||
child_type: request.child_type.clone(),
|
||||
child_info: request.child_info.clone(),
|
||||
storage_key: request.storage_key.clone().into_inner(),
|
||||
keys: request.keys.clone(),
|
||||
};
|
||||
api::v1::light::request::Request::RemoteReadChildRequest(r)
|
||||
@@ -1113,7 +1098,8 @@ fn serialize_request<B: Block>(request: &Request<B>) -> Result<Vec<u8>, prost::E
|
||||
last: request.last_block.1.encode(),
|
||||
min: request.tries_roots.1.encode(),
|
||||
max: request.max_block.1.encode(),
|
||||
storage_key: request.storage_key.clone().unwrap_or_default(),
|
||||
storage_key: request.storage_key.clone().map(|s| s.into_inner())
|
||||
.unwrap_or_default(),
|
||||
key: request.key.clone(),
|
||||
};
|
||||
api::v1::light::request::Request::RemoteChangesRequest(r)
|
||||
@@ -1343,8 +1329,6 @@ mod tests {
|
||||
use super::{Event, LightClientHandler, Request, Response, OutboundProtocol, PeerStatus};
|
||||
use void::Void;
|
||||
|
||||
const CHILD_INFO: ChildInfo<'static> = ChildInfo::new_default(b"foobarbaz");
|
||||
|
||||
type Block = sp_runtime::generic::Block<Header<u64, BlakeTwo256>, substrate_test_runtime::Extrinsic>;
|
||||
type Handler = LightClientHandler<Block>;
|
||||
type Swarm = libp2p::swarm::Swarm<Handler>;
|
||||
@@ -1894,15 +1878,13 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn receives_remote_read_child_response() {
|
||||
let info = CHILD_INFO.info();
|
||||
let mut chan = oneshot::channel();
|
||||
let child_info = ChildInfo::new_default(&b":child_storage:default:sub"[..]);
|
||||
let request = fetcher::RemoteReadChildRequest {
|
||||
header: dummy_header(),
|
||||
block: Default::default(),
|
||||
storage_key: b":child_storage:sub".to_vec(),
|
||||
storage_key: child_info.prefixed_storage_key(),
|
||||
keys: vec![b":key".to_vec()],
|
||||
child_info: info.0.to_vec(),
|
||||
child_type: info.1,
|
||||
retry_count: None,
|
||||
};
|
||||
issue_request(Request::ReadChild { request, sender: chan.0 });
|
||||
@@ -1997,15 +1979,13 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn send_receive_read_child() {
|
||||
let info = CHILD_INFO.info();
|
||||
let chan = oneshot::channel();
|
||||
let child_info = ChildInfo::new_default(&b":child_storage:default:sub"[..]);
|
||||
let request = fetcher::RemoteReadChildRequest {
|
||||
header: dummy_header(),
|
||||
block: Default::default(),
|
||||
storage_key: b":child_storage:sub".to_vec(),
|
||||
storage_key: child_info.prefixed_storage_key(),
|
||||
keys: vec![b":key".to_vec()],
|
||||
child_info: info.0.to_vec(),
|
||||
child_type: info.1,
|
||||
retry_count: None,
|
||||
};
|
||||
send_receive(Request::ReadChild { request, sender: chan.0 });
|
||||
|
||||
@@ -477,11 +477,6 @@ pub mod generic {
|
||||
pub block: H,
|
||||
/// Child Storage key.
|
||||
pub storage_key: Vec<u8>,
|
||||
/// Child trie source information.
|
||||
pub child_info: Vec<u8>,
|
||||
/// Child type, its required to resolve `child_info`
|
||||
/// content and choose child implementation.
|
||||
pub child_type: u32,
|
||||
/// Storage key.
|
||||
pub keys: Vec<Vec<u8>>,
|
||||
}
|
||||
|
||||
@@ -67,13 +67,9 @@ message RemoteReadResponse {
|
||||
message RemoteReadChildRequest {
|
||||
// Block at which to perform call.
|
||||
bytes block = 2;
|
||||
// Child Storage key.
|
||||
// Child Storage key, this is relative
|
||||
// to the child type storage location.
|
||||
bytes storage_key = 3;
|
||||
// Child trie source information.
|
||||
bytes child_info = 4;
|
||||
/// Child type, its required to resolve `child_info`
|
||||
/// content and choose child implementation.
|
||||
uint32 child_type = 5;
|
||||
// Storage keys.
|
||||
repeated bytes keys = 6;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
// Copyright 2017-2020 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Substrate is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Substrate is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Substrate state API.
|
||||
|
||||
use jsonrpc_derive::rpc;
|
||||
use sp_core::storage::{StorageKey, PrefixedStorageKey, StorageData};
|
||||
use crate::state::error::FutureResult;
|
||||
|
||||
pub use self::gen_client::Client as ChildStateClient;
|
||||
|
||||
/// Substrate child state API
|
||||
///
|
||||
/// Note that all `PrefixedStorageKey` are desierialized
|
||||
/// from json and not guaranted valid.
|
||||
#[rpc]
|
||||
pub trait ChildStateApi<Hash> {
|
||||
/// RPC Metadata
|
||||
type Metadata;
|
||||
|
||||
/// Returns the keys with prefix from a child storage, leave empty to get all the keys
|
||||
#[rpc(name = "childstate_getKeys")]
|
||||
fn storage_keys(
|
||||
&self,
|
||||
child_storage_key: PrefixedStorageKey,
|
||||
prefix: StorageKey,
|
||||
hash: Option<Hash>
|
||||
) -> FutureResult<Vec<StorageKey>>;
|
||||
|
||||
/// Returns a child storage entry at a specific block's state.
|
||||
#[rpc(name = "childstate_getStorage")]
|
||||
fn storage(
|
||||
&self,
|
||||
child_storage_key: PrefixedStorageKey,
|
||||
key: StorageKey,
|
||||
hash: Option<Hash>
|
||||
) -> FutureResult<Option<StorageData>>;
|
||||
|
||||
/// Returns the hash of a child storage entry at a block's state.
|
||||
#[rpc(name = "childstate_getStorageHash")]
|
||||
fn storage_hash(
|
||||
&self,
|
||||
child_storage_key: PrefixedStorageKey,
|
||||
key: StorageKey,
|
||||
hash: Option<Hash>
|
||||
) -> FutureResult<Option<Hash>>;
|
||||
|
||||
/// Returns the size of a child storage entry at a block's state.
|
||||
#[rpc(name = "childstate_getStorageSize")]
|
||||
fn storage_size(
|
||||
&self,
|
||||
child_storage_key: PrefixedStorageKey,
|
||||
key: StorageKey,
|
||||
hash: Option<Hash>
|
||||
) -> FutureResult<Option<u64>>;
|
||||
}
|
||||
@@ -34,4 +34,5 @@ pub mod author;
|
||||
pub mod chain;
|
||||
pub mod offchain;
|
||||
pub mod state;
|
||||
pub mod child_state;
|
||||
pub mod system;
|
||||
|
||||
@@ -72,50 +72,6 @@ pub trait StateApi<Hash> {
|
||||
#[rpc(name = "state_getStorageSize", alias("state_getStorageSizeAt"))]
|
||||
fn storage_size(&self, key: StorageKey, hash: Option<Hash>) -> FutureResult<Option<u64>>;
|
||||
|
||||
/// Returns the keys with prefix from a child storage, leave empty to get all the keys
|
||||
#[rpc(name = "state_getChildKeys")]
|
||||
fn child_storage_keys(
|
||||
&self,
|
||||
child_storage_key: StorageKey,
|
||||
child_info: StorageKey,
|
||||
child_type: u32,
|
||||
prefix: StorageKey,
|
||||
hash: Option<Hash>
|
||||
) -> FutureResult<Vec<StorageKey>>;
|
||||
|
||||
/// Returns a child storage entry at a specific block's state.
|
||||
#[rpc(name = "state_getChildStorage")]
|
||||
fn child_storage(
|
||||
&self,
|
||||
child_storage_key: StorageKey,
|
||||
child_info: StorageKey,
|
||||
child_type: u32,
|
||||
key: StorageKey,
|
||||
hash: Option<Hash>
|
||||
) -> FutureResult<Option<StorageData>>;
|
||||
|
||||
/// Returns the hash of a child storage entry at a block's state.
|
||||
#[rpc(name = "state_getChildStorageHash")]
|
||||
fn child_storage_hash(
|
||||
&self,
|
||||
child_storage_key: StorageKey,
|
||||
child_info: StorageKey,
|
||||
child_type: u32,
|
||||
key: StorageKey,
|
||||
hash: Option<Hash>
|
||||
) -> FutureResult<Option<Hash>>;
|
||||
|
||||
/// Returns the size of a child storage entry at a block's state.
|
||||
#[rpc(name = "state_getChildStorageSize")]
|
||||
fn child_storage_size(
|
||||
&self,
|
||||
child_storage_key: StorageKey,
|
||||
child_info: StorageKey,
|
||||
child_type: u32,
|
||||
key: StorageKey,
|
||||
hash: Option<Hash>
|
||||
) -> FutureResult<Option<u64>>;
|
||||
|
||||
/// Returns the runtime metadata as an opaque blob.
|
||||
#[rpc(name = "state_getMetadata")]
|
||||
fn metadata(&self, hash: Option<Hash>) -> FutureResult<Bytes>;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -1015,7 +1015,7 @@ ServiceBuilder<
|
||||
|
||||
let subscriptions = sc_rpc::Subscriptions::new(Arc::new(tasks_builder.spawn_handle()));
|
||||
|
||||
let (chain, state) = if let (Some(remote_backend), Some(on_demand)) =
|
||||
let (chain, state, child_state) = if let (Some(remote_backend), Some(on_demand)) =
|
||||
(remote_backend.as_ref(), on_demand.as_ref()) {
|
||||
// Light clients
|
||||
let chain = sc_rpc::chain::new_light(
|
||||
@@ -1024,19 +1024,19 @@ ServiceBuilder<
|
||||
remote_backend.clone(),
|
||||
on_demand.clone()
|
||||
);
|
||||
let state = sc_rpc::state::new_light(
|
||||
let (state, child_state) = sc_rpc::state::new_light(
|
||||
client.clone(),
|
||||
subscriptions.clone(),
|
||||
remote_backend.clone(),
|
||||
on_demand.clone()
|
||||
);
|
||||
(chain, state)
|
||||
(chain, state, child_state)
|
||||
|
||||
} else {
|
||||
// Full nodes
|
||||
let chain = sc_rpc::chain::new_full(client.clone(), subscriptions.clone());
|
||||
let state = sc_rpc::state::new_full(client.clone(), subscriptions.clone());
|
||||
(chain, state)
|
||||
let (state, child_state) = sc_rpc::state::new_full(client.clone(), subscriptions.clone());
|
||||
(chain, state, child_state)
|
||||
};
|
||||
|
||||
let author = sc_rpc::author::Author::new(
|
||||
@@ -1059,6 +1059,7 @@ ServiceBuilder<
|
||||
|
||||
sc_rpc_server::rpc_handler((
|
||||
state::StateApi::to_delegate(state),
|
||||
state::ChildStateApi::to_delegate(child_state),
|
||||
chain::ChainApi::to_delegate(chain),
|
||||
maybe_offchain_rpc,
|
||||
author::AuthorApi::to_delegate(author),
|
||||
|
||||
@@ -25,8 +25,8 @@ use parking_lot::{Mutex, RwLock};
|
||||
use codec::{Encode, Decode};
|
||||
use hash_db::Prefix;
|
||||
use sp_core::{
|
||||
ChangesTrieConfiguration, convert_hash, traits::CodeExecutor,
|
||||
NativeOrEncoded, storage::{StorageKey, StorageData, well_known_keys, ChildInfo},
|
||||
ChangesTrieConfiguration, convert_hash, traits::CodeExecutor, NativeOrEncoded,
|
||||
storage::{StorageKey, PrefixedStorageKey, StorageData, well_known_keys, ChildInfo},
|
||||
};
|
||||
use sc_telemetry::{telemetry, SUBSTRATE_INFO};
|
||||
use sp_runtime::{
|
||||
@@ -344,7 +344,7 @@ impl<B, E, Block, RA> Client<B, E, Block, RA> where
|
||||
last: Block::Hash,
|
||||
min: Block::Hash,
|
||||
max: Block::Hash,
|
||||
storage_key: Option<&StorageKey>,
|
||||
storage_key: Option<&PrefixedStorageKey>,
|
||||
key: &StorageKey,
|
||||
cht_size: NumberFor<Block>,
|
||||
) -> sp_blockchain::Result<ChangesProof<Block::Header>> {
|
||||
@@ -393,7 +393,7 @@ impl<B, E, Block, RA> Client<B, E, Block, RA> where
|
||||
fn with_cached_changed_keys(
|
||||
&self,
|
||||
root: &Block::Hash,
|
||||
functor: &mut dyn FnMut(&HashMap<Option<Vec<u8>>, HashSet<Vec<u8>>>),
|
||||
functor: &mut dyn FnMut(&HashMap<Option<PrefixedStorageKey>, HashSet<Vec<u8>>>),
|
||||
) -> bool {
|
||||
self.storage.with_cached_changed_keys(root, functor)
|
||||
}
|
||||
@@ -438,7 +438,7 @@ impl<B, E, Block, RA> Client<B, E, Block, RA> where
|
||||
number: last_number,
|
||||
},
|
||||
max_number,
|
||||
storage_key.as_ref().map(|x| &x.0[..]),
|
||||
storage_key,
|
||||
&key.0,
|
||||
)
|
||||
.map_err(|err| sp_blockchain::Error::ChangesTrieAccessFailed(err))?;
|
||||
@@ -1109,12 +1109,11 @@ impl<B, E, Block, RA> ProofProvider<Block> for Client<B, E, Block, RA> where
|
||||
fn read_child_proof(
|
||||
&self,
|
||||
id: &BlockId<Block>,
|
||||
storage_key: &[u8],
|
||||
child_info: ChildInfo,
|
||||
child_info: &ChildInfo,
|
||||
keys: &mut dyn Iterator<Item=&[u8]>,
|
||||
) -> sp_blockchain::Result<StorageProof> {
|
||||
self.state_at(id)
|
||||
.and_then(|state| prove_child_read(state, storage_key, child_info, keys)
|
||||
.and_then(|state| prove_child_read(state, child_info, keys)
|
||||
.map_err(Into::into))
|
||||
}
|
||||
|
||||
@@ -1156,7 +1155,7 @@ impl<B, E, Block, RA> ProofProvider<Block> for Client<B, E, Block, RA> where
|
||||
last: Block::Hash,
|
||||
min: Block::Hash,
|
||||
max: Block::Hash,
|
||||
storage_key: Option<&StorageKey>,
|
||||
storage_key: Option<&PrefixedStorageKey>,
|
||||
key: &StorageKey,
|
||||
) -> sp_blockchain::Result<ChangesProof<Block::Header>> {
|
||||
self.key_changes_proof_with_cht_size(
|
||||
@@ -1286,46 +1285,40 @@ impl<B, E, Block, RA> StorageProvider<Block, B> for Client<B, E, Block, RA> wher
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
fn child_storage_keys(
|
||||
&self,
|
||||
id: &BlockId<Block>,
|
||||
child_storage_key: &StorageKey,
|
||||
child_info: ChildInfo,
|
||||
child_info: &ChildInfo,
|
||||
key_prefix: &StorageKey
|
||||
) -> sp_blockchain::Result<Vec<StorageKey>> {
|
||||
let keys = self.state_at(id)?
|
||||
.child_keys(&child_storage_key.0, child_info, &key_prefix.0)
|
||||
.child_keys(child_info, &key_prefix.0)
|
||||
.into_iter()
|
||||
.map(StorageKey)
|
||||
.collect();
|
||||
Ok(keys)
|
||||
}
|
||||
|
||||
|
||||
fn child_storage(
|
||||
&self,
|
||||
id: &BlockId<Block>,
|
||||
storage_key: &StorageKey,
|
||||
child_info: ChildInfo,
|
||||
child_info: &ChildInfo,
|
||||
key: &StorageKey
|
||||
) -> sp_blockchain::Result<Option<StorageData>> {
|
||||
Ok(self.state_at(id)?
|
||||
.child_storage(&storage_key.0, child_info, &key.0)
|
||||
.child_storage(child_info, &key.0)
|
||||
.map_err(|e| sp_blockchain::Error::from_state(Box::new(e)))?
|
||||
.map(StorageData))
|
||||
}
|
||||
|
||||
|
||||
fn child_storage_hash(
|
||||
&self,
|
||||
id: &BlockId<Block>,
|
||||
storage_key: &StorageKey,
|
||||
child_info: ChildInfo,
|
||||
child_info: &ChildInfo,
|
||||
key: &StorageKey
|
||||
) -> sp_blockchain::Result<Option<Block::Hash>> {
|
||||
Ok(self.state_at(id)?
|
||||
.child_storage_hash(&storage_key.0, child_info, &key.0)
|
||||
.child_storage_hash(child_info, &key.0)
|
||||
.map_err(|e| sp_blockchain::Error::from_state(Box::new(e)))?
|
||||
)
|
||||
}
|
||||
@@ -1361,7 +1354,7 @@ impl<B, E, Block, RA> StorageProvider<Block, B> for Client<B, E, Block, RA> wher
|
||||
&self,
|
||||
first: NumberFor<Block>,
|
||||
last: BlockId<Block>,
|
||||
storage_key: Option<&StorageKey>,
|
||||
storage_key: Option<&PrefixedStorageKey>,
|
||||
key: &StorageKey
|
||||
) -> sp_blockchain::Result<Vec<(NumberFor<Block>, u32)>> {
|
||||
let last_number = self.backend.blockchain().expect_block_number_from_id(&last)?;
|
||||
@@ -1392,7 +1385,7 @@ impl<B, E, Block, RA> StorageProvider<Block, B> for Client<B, E, Block, RA> wher
|
||||
range_first,
|
||||
&range_anchor,
|
||||
best_number,
|
||||
storage_key.as_ref().map(|x| &x.0[..]),
|
||||
storage_key,
|
||||
&key.0)
|
||||
.and_then(|r| r.map(|r| r.map(|(block, tx)| (block, tx))).collect::<Result<_, _>>())
|
||||
.map_err(|err| sp_blockchain::Error::ChangesTrieAccessFailed(err))?;
|
||||
|
||||
@@ -516,9 +516,9 @@ impl<Block: BlockT> backend::BlockImportOperation<Block> for BlockImportOperatio
|
||||
fn reset_storage(&mut self, storage: Storage) -> sp_blockchain::Result<Block::Hash> {
|
||||
check_genesis_storage(&storage)?;
|
||||
|
||||
let child_delta = storage.children.into_iter()
|
||||
.map(|(storage_key, child_content)|
|
||||
(storage_key, child_content.data.into_iter().map(|(k, v)| (k, Some(v))), child_content.child_info));
|
||||
let child_delta = storage.children_default.into_iter()
|
||||
.map(|(_storage_key, child_content)|
|
||||
(child_content.child_info, child_content.data.into_iter().map(|(k, v)| (k, Some(v)))));
|
||||
|
||||
let (root, transaction) = self.old_state.full_storage_root(
|
||||
storage.top.into_iter().map(|(k, v)| (k, Some(v))),
|
||||
@@ -725,8 +725,9 @@ pub fn check_genesis_storage(storage: &Storage) -> sp_blockchain::Result<()> {
|
||||
return Err(sp_blockchain::Error::GenesisInvalid.into());
|
||||
}
|
||||
|
||||
if storage.children.keys().any(|child_key| !well_known_keys::is_child_storage_key(&child_key)) {
|
||||
return Err(sp_blockchain::Error::GenesisInvalid.into());
|
||||
if storage.children_default.keys()
|
||||
.any(|child_key| !well_known_keys::is_child_storage_key(&child_key)) {
|
||||
return Err(sp_blockchain::Error::GenesisInvalid.into());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -24,7 +24,7 @@ use parking_lot::RwLock;
|
||||
use codec::{Decode, Encode};
|
||||
|
||||
use sp_core::ChangesTrieConfiguration;
|
||||
use sp_core::storage::{well_known_keys, ChildInfo, OwnedChildInfo};
|
||||
use sp_core::storage::{well_known_keys, ChildInfo};
|
||||
use sp_core::offchain::storage::InMemOffchainStorage;
|
||||
use sp_state_machine::{
|
||||
Backend as StateBackend, TrieBackend, InMemoryBackend, ChangesTrieTransaction,
|
||||
@@ -312,17 +312,17 @@ impl<S, Block> BlockImportOperation<Block> for ImportOperation<Block, S>
|
||||
self.changes_trie_config_update = Some(changes_trie_config);
|
||||
|
||||
// this is only called when genesis block is imported => shouldn't be performance bottleneck
|
||||
let mut storage: HashMap<Option<(Vec<u8>, OwnedChildInfo)>, _> = HashMap::new();
|
||||
let mut storage: HashMap<Option<ChildInfo>, _> = HashMap::new();
|
||||
storage.insert(None, input.top);
|
||||
|
||||
// create a list of children keys to re-compute roots for
|
||||
let child_delta = input.children.iter()
|
||||
.map(|(storage_key, storage_child)| (storage_key.clone(), None, storage_child.child_info.clone()))
|
||||
let child_delta = input.children_default.iter()
|
||||
.map(|(_storage_key, storage_child)| (storage_child.child_info.clone(), None))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// make sure to persist the child storage
|
||||
for (child_key, storage_child) in input.children {
|
||||
storage.insert(Some((child_key, storage_child.child_info)), storage_child.data);
|
||||
for (_child_key, storage_child) in input.children_default {
|
||||
storage.insert(Some(storage_child.child_info), storage_child.data);
|
||||
}
|
||||
|
||||
let storage_update = InMemoryBackend::from(storage);
|
||||
@@ -386,13 +386,12 @@ impl<H: Hasher> StateBackend<H> for GenesisOrUnavailableState<H>
|
||||
|
||||
fn child_storage(
|
||||
&self,
|
||||
storage_key: &[u8],
|
||||
child_info: ChildInfo,
|
||||
child_info: &ChildInfo,
|
||||
key: &[u8],
|
||||
) -> ClientResult<Option<Vec<u8>>> {
|
||||
match *self {
|
||||
GenesisOrUnavailableState::Genesis(ref state) =>
|
||||
Ok(state.child_storage(storage_key, child_info, key).expect(IN_MEMORY_EXPECT_PROOF)),
|
||||
Ok(state.child_storage(child_info, key).expect(IN_MEMORY_EXPECT_PROOF)),
|
||||
GenesisOrUnavailableState::Unavailable => Err(ClientError::NotAvailableOnLightClient),
|
||||
}
|
||||
}
|
||||
@@ -407,13 +406,12 @@ impl<H: Hasher> StateBackend<H> for GenesisOrUnavailableState<H>
|
||||
|
||||
fn next_child_storage_key(
|
||||
&self,
|
||||
storage_key: &[u8],
|
||||
child_info: ChildInfo,
|
||||
child_info: &ChildInfo,
|
||||
key: &[u8],
|
||||
) -> Result<Option<Vec<u8>>, Self::Error> {
|
||||
match *self {
|
||||
GenesisOrUnavailableState::Genesis(ref state) => Ok(
|
||||
state.next_child_storage_key(storage_key, child_info, key)
|
||||
state.next_child_storage_key(child_info, key)
|
||||
.expect(IN_MEMORY_EXPECT_PROOF)
|
||||
),
|
||||
GenesisOrUnavailableState::Unavailable => Err(ClientError::NotAvailableOnLightClient),
|
||||
@@ -436,27 +434,25 @@ impl<H: Hasher> StateBackend<H> for GenesisOrUnavailableState<H>
|
||||
|
||||
fn for_keys_in_child_storage<A: FnMut(&[u8])>(
|
||||
&self,
|
||||
storage_key: &[u8],
|
||||
child_info: ChildInfo,
|
||||
child_info: &ChildInfo,
|
||||
action: A,
|
||||
) {
|
||||
match *self {
|
||||
GenesisOrUnavailableState::Genesis(ref state) =>
|
||||
state.for_keys_in_child_storage(storage_key, child_info, action),
|
||||
state.for_keys_in_child_storage(child_info, action),
|
||||
GenesisOrUnavailableState::Unavailable => (),
|
||||
}
|
||||
}
|
||||
|
||||
fn for_child_keys_with_prefix<A: FnMut(&[u8])>(
|
||||
&self,
|
||||
storage_key: &[u8],
|
||||
child_info: ChildInfo,
|
||||
child_info: &ChildInfo,
|
||||
prefix: &[u8],
|
||||
action: A,
|
||||
) {
|
||||
match *self {
|
||||
GenesisOrUnavailableState::Genesis(ref state) =>
|
||||
state.for_child_keys_with_prefix(storage_key, child_info, prefix, action),
|
||||
state.for_child_keys_with_prefix(child_info, prefix, action),
|
||||
GenesisOrUnavailableState::Unavailable => (),
|
||||
}
|
||||
}
|
||||
@@ -474,8 +470,7 @@ impl<H: Hasher> StateBackend<H> for GenesisOrUnavailableState<H>
|
||||
|
||||
fn child_storage_root<I>(
|
||||
&self,
|
||||
storage_key: &[u8],
|
||||
child_info: ChildInfo,
|
||||
child_info: &ChildInfo,
|
||||
delta: I,
|
||||
) -> (H::Out, bool, Self::Transaction)
|
||||
where
|
||||
@@ -483,7 +478,7 @@ impl<H: Hasher> StateBackend<H> for GenesisOrUnavailableState<H>
|
||||
{
|
||||
match *self {
|
||||
GenesisOrUnavailableState::Genesis(ref state) => {
|
||||
let (root, is_equal, _) = state.child_storage_root(storage_key, child_info, delta);
|
||||
let (root, is_equal, _) = state.child_storage_root(child_info, delta);
|
||||
(root, is_equal, Default::default())
|
||||
},
|
||||
GenesisOrUnavailableState::Unavailable =>
|
||||
|
||||
@@ -23,6 +23,7 @@ use std::marker::PhantomData;
|
||||
use hash_db::{HashDB, Hasher, EMPTY_PREFIX};
|
||||
use codec::{Decode, Encode};
|
||||
use sp_core::{convert_hash, traits::CodeExecutor};
|
||||
use sp_core::storage::{ChildInfo, ChildType};
|
||||
use sp_runtime::traits::{
|
||||
Block as BlockT, Header as HeaderT, Hash, HashFor, NumberFor,
|
||||
AtLeast32Bit, CheckedConversion,
|
||||
@@ -135,7 +136,7 @@ impl<E, H, B: BlockT, S: BlockchainStorage<B>> LightDataChecker<E, H, B, S> {
|
||||
number: request.last_block.0,
|
||||
},
|
||||
remote_max_block,
|
||||
request.storage_key.as_ref().map(Vec::as_slice),
|
||||
request.storage_key.as_ref(),
|
||||
&request.key)
|
||||
.map_err(|err| ClientError::ChangesTrieAccessFailed(err))?;
|
||||
result.extend(result_range);
|
||||
@@ -242,10 +243,14 @@ impl<E, Block, H, S> FetchChecker<Block> for LightDataChecker<E, H, Block, S>
|
||||
request: &RemoteReadChildRequest<Block::Header>,
|
||||
remote_proof: StorageProof,
|
||||
) -> ClientResult<HashMap<Vec<u8>, Option<Vec<u8>>>> {
|
||||
let child_info = match ChildType::from_prefixed_key(&request.storage_key) {
|
||||
Some((ChildType::ParentKeyId, storage_key)) => ChildInfo::new_default(storage_key),
|
||||
None => return Err("Invalid child type".into()),
|
||||
};
|
||||
read_child_proof_check::<H, _>(
|
||||
convert_hash(request.header.state_root()),
|
||||
remote_proof,
|
||||
&request.storage_key,
|
||||
&child_info,
|
||||
request.keys.iter(),
|
||||
).map_err(Into::into)
|
||||
}
|
||||
@@ -360,8 +365,6 @@ pub mod tests {
|
||||
use sc_client_api::{StorageProvider, ProofProvider};
|
||||
use sc_block_builder::BlockBuilderProvider;
|
||||
|
||||
const CHILD_INFO_1: ChildInfo<'static> = ChildInfo::new_default(b"unique_id_1");
|
||||
|
||||
type TestChecker = LightDataChecker<
|
||||
NativeExecutor<substrate_test_runtime_client::LocalExecutor>,
|
||||
BlakeTwo256,
|
||||
@@ -411,11 +414,12 @@ pub mod tests {
|
||||
fn prepare_for_read_child_proof_check() -> (TestChecker, Header, StorageProof, Vec<u8>) {
|
||||
use substrate_test_runtime_client::DefaultTestClientBuilderExt;
|
||||
use substrate_test_runtime_client::TestClientBuilderExt;
|
||||
let child_info = ChildInfo::new_default(b"child1");
|
||||
let child_info = &child_info;
|
||||
// prepare remote client
|
||||
let remote_client = substrate_test_runtime_client::TestClientBuilder::new()
|
||||
.add_extra_child_storage(
|
||||
b":child_storage:default:child1".to_vec(),
|
||||
CHILD_INFO_1,
|
||||
child_info,
|
||||
b"key1".to_vec(),
|
||||
b"value1".to_vec(),
|
||||
).build();
|
||||
@@ -428,15 +432,13 @@ pub mod tests {
|
||||
// 'fetch' child read proof from remote node
|
||||
let child_value = remote_client.child_storage(
|
||||
&remote_block_id,
|
||||
&StorageKey(b":child_storage:default:child1".to_vec()),
|
||||
CHILD_INFO_1,
|
||||
child_info,
|
||||
&StorageKey(b"key1".to_vec()),
|
||||
).unwrap().unwrap().0;
|
||||
assert_eq!(b"value1"[..], child_value[..]);
|
||||
let remote_read_proof = remote_client.read_child_proof(
|
||||
&remote_block_id,
|
||||
b":child_storage:default:child1",
|
||||
CHILD_INFO_1,
|
||||
child_info,
|
||||
&mut std::iter::once("key1".as_bytes()),
|
||||
).unwrap();
|
||||
|
||||
@@ -510,20 +512,18 @@ pub mod tests {
|
||||
|
||||
#[test]
|
||||
fn storage_child_read_proof_is_generated_and_checked() {
|
||||
let child_info = ChildInfo::new_default(&b"child1"[..]);
|
||||
let (
|
||||
local_checker,
|
||||
remote_block_header,
|
||||
remote_read_proof,
|
||||
result,
|
||||
) = prepare_for_read_child_proof_check();
|
||||
let child_infos = CHILD_INFO_1.info();
|
||||
assert_eq!((&local_checker as &dyn FetchChecker<Block>).check_read_child_proof(
|
||||
&RemoteReadChildRequest::<Header> {
|
||||
block: remote_block_header.hash(),
|
||||
header: remote_block_header,
|
||||
storage_key: b":child_storage:default:child1".to_vec(),
|
||||
child_info: child_infos.0.to_vec(),
|
||||
child_type: child_infos.1,
|
||||
storage_key: child_info.prefixed_storage_key(),
|
||||
keys: vec![b"key1".to_vec()],
|
||||
retry_count: None,
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user