diff --git a/client/rpc/src/state/mod.rs b/client/rpc/src/state/mod.rs index ded87c73dc8f7..01c7c5f1eb40c 100644 --- a/client/rpc/src/state/mod.rs +++ b/client/rpc/src/state/mod.rs @@ -97,14 +97,14 @@ pub trait StateBackend: Send + Sync + 'static ) -> FutureResult>; /// 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, key: StorageKey, - ) -> FutureResult> { - Box::new(self.storage(block, key) - .map(|x| x.map(|x| x.0.len() as u64))) - } + ) -> FutureResult>; /// Returns the runtime metadata as an opaque blob. fn metadata(&self, block: Option) -> FutureResult; diff --git a/client/rpc/src/state/state_full.rs b/client/rpc/src/state/state_full.rs index 3a5580c539a4c..fda73cea27110 100644 --- a/client/rpc/src/state/state_full.rs +++ b/client/rpc/src/state/state_full.rs @@ -298,6 +298,36 @@ impl StateBackend for FullState, + key: StorageKey, + ) -> FutureResult> { + 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::(); + if item_sum > 0 { + Some(item_sum) + } else { + None + } + }) + .map_err(client_err) + )) + } + fn storage_hash( &self, block: Option, diff --git a/client/rpc/src/state/state_light.rs b/client/rpc/src/state/state_light.rs index 01fd1c16018ff..8f4dce08b3fb6 100644 --- a/client/rpc/src/state/state_light.rs +++ b/client/rpc/src/state/state_light.rs @@ -214,6 +214,14 @@ impl StateBackend for LightState, + _: StorageKey, + ) -> FutureResult> { + Box::new(result(Err(client_err(ClientError::NotAvailableOnLightClient)))) + } + fn storage( &self, block: Option, diff --git a/client/rpc/src/state/tests.rs b/client/rpc/src/state/tests.rs index 0cc16ce8d5e92..b6677a1f2ffb4 100644 --- a/client/rpc/src/state/tests.rs +++ b/client/rpc/src/state/tests.rs @@ -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]