state_getSize RPC for storage maps (#6847)

* Fancy compact encode/decode impl for compact solution

* Make it optional

* Remove extra file

* Update primitives/npos-elections/compact/src/lib.rs

Co-authored-by: Guillaume Thiolliere <gui.thiolliere@gmail.com>

* Final fixes.

* getSize rpc should work for maps as well

* Fix future types

* Remove minimum_validator_count stale const

* Update client/rpc/src/state/mod.rs

Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>

* "Optimize" `storage_size`

* Remove unused import

* Update doc

Co-authored-by: Guillaume Thiolliere <gui.thiolliere@gmail.com>
Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>
Co-authored-by: Bastian Köcher <git@kchr.de>
This commit is contained in:
Kian Paimani
2020-08-11 14:09:52 +02:00
committed by GitHub
parent 1519da95d7
commit b0342f0b12
4 changed files with 49 additions and 5 deletions
+4 -4
View File
@@ -97,14 +97,14 @@ pub trait StateBackend<Block: BlockT, Client>: Send + Sync + 'static
) -> FutureResult<Option<Block::Hash>>;
/// Returns the size of a storage entry at a block's state.
///
/// If data is available at `key`, it is returned. Else, the sum of values who's key has `key`
/// prefix is returned, i.e. all the storage (double) maps that have this prefix.
fn storage_size(
&self,
block: Option<Block::Hash>,
key: StorageKey,
) -> FutureResult<Option<u64>> {
Box::new(self.storage(block, key)
.map(|x| x.map(|x| x.0.len() as u64)))
}
) -> FutureResult<Option<u64>>;
/// Returns the runtime metadata as an opaque blob.
fn metadata(&self, block: Option<Block::Hash>) -> FutureResult<Bytes>;
@@ -298,6 +298,36 @@ impl<BE, Block, Client> StateBackend<Block, Client> for FullState<BE, Block, Cli
.map_err(client_err)))
}
fn storage_size(
&self,
block: Option<Block::Hash>,
key: StorageKey,
) -> FutureResult<Option<u64>> {
let block = match self.block_or_best(block) {
Ok(b) => b,
Err(e) => return Box::new(result(Err(client_err(e)))),
};
match self.client.storage(&BlockId::Hash(block), &key) {
Ok(Some(d)) => return Box::new(result(Ok(Some(d.0.len() as u64)))),
Err(e) => return Box::new(result(Err(client_err(e)))),
Ok(None) => {},
}
Box::new(result(
self.client.storage_pairs(&BlockId::Hash(block), &key)
.map(|kv| {
let item_sum = kv.iter().map(|(_, v)| v.0.len() as u64).sum::<u64>();
if item_sum > 0 {
Some(item_sum)
} else {
None
}
})
.map_err(client_err)
))
}
fn storage_hash(
&self,
block: Option<Block::Hash>,
@@ -214,6 +214,14 @@ impl<Block, F, Client> StateBackend<Block, Client> for LightState<Block, F, Clie
Box::new(result(Err(client_err(ClientError::NotAvailableOnLightClient))))
}
fn storage_size(
&self,
_: Option<Block::Hash>,
_: StorageKey,
) -> FutureResult<Option<u64>> {
Box::new(result(Err(client_err(ClientError::NotAvailableOnLightClient))))
}
fn storage(
&self,
block: Option<Block::Hash>,
+7 -1
View File
@@ -53,6 +53,9 @@ fn should_return_storage() {
let client = TestClientBuilder::new()
.add_extra_storage(KEY.to_vec(), VALUE.to_vec())
.add_extra_child_storage(&child_info, KEY.to_vec(), CHILD_VALUE.to_vec())
// similar to a map with two keys
.add_extra_storage(b":map:acc1".to_vec(), vec![1, 2])
.add_extra_storage(b":map:acc2".to_vec(), vec![1, 2, 3])
.build();
let genesis_hash = client.genesis_hash();
let (client, child) = new_full(Arc::new(client), SubscriptionManager::new(Arc::new(TaskExecutor)));
@@ -72,6 +75,10 @@ fn should_return_storage() {
client.storage_size(key.clone(), None).wait().unwrap().unwrap() as usize,
VALUE.len(),
);
assert_eq!(
client.storage_size(StorageKey(b":map".to_vec()), None).wait().unwrap().unwrap() as usize,
2 + 3,
);
assert_eq!(
executor::block_on(
child.storage(prefixed_storage_key(), key, Some(genesis_hash).into())
@@ -80,7 +87,6 @@ fn should_return_storage() {
).unwrap().unwrap() as usize,
CHILD_VALUE.len(),
);
}
#[test]