Child trie api changes BREAKING (#4857)

Co-Authored-By: thiolliere <gui.thiolliere@gmail.com>
This commit is contained in:
cheme
2020-04-20 15:21:22 +02:00
committed by GitHub
parent 7d9aa81bfc
commit 4ffcf98d8d
64 changed files with 1514 additions and 1655 deletions
+6 -8
View File
@@ -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)>>;
}
+3 -8
View File
@@ -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.
+3 -4
View File
@@ -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>>;
}
+14 -33
View File
@@ -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,
};
+16 -24
View File
@@ -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)
}
+20 -33
View File
@@ -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");
+29 -43
View File
@@ -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);
}
+32 -39
View File
@@ -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>>;
}
+1
View File
@@ -34,4 +34,5 @@ pub mod author;
pub mod chain;
pub mod offchain;
pub mod state;
pub mod child_state;
pub mod system;
-44
View File
@@ -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>;
+111 -103
View File
@@ -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())
}
+80 -63
View File
@@ -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.
+64 -65
View File
@@ -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>,
+24 -31
View File
@@ -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);
+6 -5
View File
@@ -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),
+16 -23
View File
@@ -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))?;
+6 -5
View File
@@ -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(())
+16 -21
View File
@@ -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 =>
+14 -14
View File
@@ -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,
},