From 9202cd87e0a98d143e57d6acd80b36bd1c7eba4f Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Wed, 5 Feb 2020 17:27:50 +0100 Subject: [PATCH] Additional RPC for dumping all main storage key pairs under a prefix (#4803) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Merge branch 'gav-split-balanecs-vesting' into gav-upsub # Conflicts: # Cargo.lock # cli/Cargo.toml # collator/Cargo.toml # primitives/Cargo.toml # runtime/common/Cargo.toml # runtime/common/src/claims.rs # runtime/kusama/Cargo.toml # runtime/polkadot/Cargo.toml # service/Cargo.toml * Update client/src/client.rs * Update client/src/client.rs * Fix merge conflict Co-authored-by: Bastian Köcher --- substrate/client/rpc-api/src/state/mod.rs | 4 ++++ substrate/client/rpc/src/state/mod.rs | 15 ++++++++++++ substrate/client/rpc/src/state/state_full.rs | 11 +++++++++ substrate/client/rpc/src/state/state_light.rs | 8 +++++++ substrate/client/src/client.rs | 23 +++++++++++++++++-- 5 files changed, 59 insertions(+), 2 deletions(-) diff --git a/substrate/client/rpc-api/src/state/mod.rs b/substrate/client/rpc-api/src/state/mod.rs index 6901738efe..b2cf8ce909 100644 --- a/substrate/client/rpc-api/src/state/mod.rs +++ b/substrate/client/rpc-api/src/state/mod.rs @@ -44,6 +44,10 @@ pub trait StateApi { #[rpc(name = "state_getKeys")] fn storage_keys(&self, prefix: StorageKey, hash: Option) -> FutureResult>; + /// Returns the keys with prefix, leave empty to get all the keys + #[rpc(name = "state_getPairs")] + fn storage_pairs(&self, prefix: StorageKey, hash: Option) -> FutureResult>; + /// Returns the keys with prefix with pagination support. /// Up to `count` keys will be returned. /// If `start_key` is passed, return next keys in storage in lexicographic order. diff --git a/substrate/client/rpc/src/state/mod.rs b/substrate/client/rpc/src/state/mod.rs index df26daa929..8f621cc8af 100644 --- a/substrate/client/rpc/src/state/mod.rs +++ b/substrate/client/rpc/src/state/mod.rs @@ -63,6 +63,13 @@ pub trait StateBackend: Send + Sync + 'static prefix: StorageKey, ) -> FutureResult>; + /// Returns the keys with prefix along with their values, leave empty to get all the pairs. + fn storage_pairs( + &self, + block: Option, + prefix: StorageKey, + ) -> FutureResult>; + /// Returns the keys with prefix with pagination support. fn storage_keys_paged( &self, @@ -255,6 +262,14 @@ impl StateApi for State self.backend.storage_keys(block, key_prefix) } + fn storage_pairs( + &self, + key_prefix: StorageKey, + block: Option, + ) -> FutureResult> { + self.backend.storage_pairs(block, key_prefix) + } + fn storage_keys_paged( &self, prefix: Option, diff --git a/substrate/client/rpc/src/state/state_full.rs b/substrate/client/rpc/src/state/state_full.rs index 87c75e77a6..3d5613626e 100644 --- a/substrate/client/rpc/src/state/state_full.rs +++ b/substrate/client/rpc/src/state/state_full.rs @@ -254,6 +254,17 @@ impl StateBackend for FullState, + prefix: StorageKey, + ) -> FutureResult> { + Box::new(result( + self.block_or_best(block) + .and_then(|block| self.client.storage_pairs(&BlockId::Hash(block), &prefix)) + .map_err(client_err))) + } + fn storage_keys_paged( &self, block: Option, diff --git a/substrate/client/rpc/src/state/state_light.rs b/substrate/client/rpc/src/state/state_light.rs index f25d6e2186..7b2455a8fc 100644 --- a/substrate/client/rpc/src/state/state_light.rs +++ b/substrate/client/rpc/src/state/state_light.rs @@ -199,6 +199,14 @@ impl StateBackend for LightState, + _prefix: StorageKey, + ) -> FutureResult> { + Box::new(result(Err(client_err(ClientError::NotAvailableOnLightClient)))) + } + fn storage_keys_paged( &self, _block: Option, diff --git a/substrate/client/src/client.rs b/substrate/client/src/client.rs index ca8b0c5dd7..9e30c7b2ea 100644 --- a/substrate/client/src/client.rs +++ b/substrate/client/src/client.rs @@ -280,6 +280,22 @@ impl Client where Ok(keys) } + /// Given a `BlockId` and a key prefix, return the matching child storage keys and values in that block. + pub fn storage_pairs(&self, id: &BlockId, key_prefix: &StorageKey) + -> sp_blockchain::Result> + { + let state = self.state_at(id)?; + let keys = state + .keys(&key_prefix.0) + .into_iter() + .map(|k| { + let d = state.storage(&k).ok().flatten().unwrap_or_default(); + (StorageKey(k), StorageData(d)) + }) + .collect(); + Ok(keys) + } + /// Given a `BlockId` and a key prefix, return a `KeyIterator` iterates matching storage keys in that block. pub fn storage_keys_iter<'a>( &self, @@ -296,7 +312,9 @@ impl Client where } /// Given a `BlockId` and a key, return the value under the key in that block. - pub fn storage(&self, id: &BlockId, key: &StorageKey) -> sp_blockchain::Result> { + pub fn storage(&self, id: &BlockId, key: &StorageKey) + -> sp_blockchain::Result> + { Ok(self.state_at(id)? .storage(&key.0).map_err(|e| sp_blockchain::Error::from_state(Box::new(e)))? .map(StorageData) @@ -305,7 +323,8 @@ impl Client where /// Given a `BlockId` and a key, return the value under the hash in that block. pub fn storage_hash(&self, id: &BlockId, key: &StorageKey) - -> sp_blockchain::Result> { + -> sp_blockchain::Result> + { Ok(self.state_at(id)? .storage_hash(&key.0).map_err(|e| sp_blockchain::Error::from_state(Box::new(e)))? )