add state_getKeysPaged (#4718)

* add storage_getNextKey

* RPC storage_getKeysPages

* respect count

* use iterator

* improve

* add tests

* improve

* add doc comments

* Make prefix optional

* update error

* improve
This commit is contained in:
Xiliang Chen
2020-02-04 22:44:40 +13:00
committed by GitHub
parent 900295b020
commit febb6e29b2
6 changed files with 199 additions and 3 deletions
+30 -1
View File
@@ -24,7 +24,7 @@ mod tests;
use std::sync::Arc;
use jsonrpc_pubsub::{typed::Subscriber, SubscriptionId};
use rpc::{Result as RpcResult, futures::Future};
use rpc::{Result as RpcResult, futures::{Future, future::result}};
use sc_rpc_api::Subscriptions;
use sc_client::{Client, CallExecutor, light::{blockchain::RemoteBlockchain, fetcher::Fetcher}};
@@ -38,6 +38,8 @@ use self::error::{Error, FutureResult};
pub use sc_rpc_api::state::*;
const STORAGE_KEYS_PAGED_MAX_COUNT: u32 = 1000;
/// State backend API.
pub trait StateBackend<B, E, Block: BlockT, RA>: Send + Sync + 'static
where
@@ -61,6 +63,15 @@ pub trait StateBackend<B, E, Block: BlockT, RA>: Send + Sync + 'static
prefix: StorageKey,
) -> FutureResult<Vec<StorageKey>>;
/// Returns the keys with prefix with pagination support.
fn storage_keys_paged(
&self,
block: Option<Block::Hash>,
prefix: Option<StorageKey>,
count: u32,
start_key: Option<StorageKey>,
) -> FutureResult<Vec<StorageKey>>;
/// Returns a storage entry at a specific block's state.
fn storage(
&self,
@@ -244,6 +255,24 @@ impl<B, E, Block, RA> StateApi<Block::Hash> for State<B, E, Block, RA>
self.backend.storage_keys(block, key_prefix)
}
fn storage_keys_paged(
&self,
prefix: Option<StorageKey>,
count: u32,
start_key: Option<StorageKey>,
block: Option<Block::Hash>,
) -> FutureResult<Vec<StorageKey>> {
if count > STORAGE_KEYS_PAGED_MAX_COUNT {
return Box::new(result(Err(
Error::InvalidCount {
value: count,
max: STORAGE_KEYS_PAGED_MAX_COUNT,
}
)));
}
self.backend.storage_keys_paged(block, prefix, count, start_key)
}
fn storage(&self, key: StorageKey, block: Option<Block::Hash>) -> FutureResult<Option<StorageData>> {
self.backend.storage(block, key)
}
@@ -254,6 +254,24 @@ impl<B, E, Block, RA> StateBackend<B, E, Block, RA> for FullState<B, E, Block, R
.map_err(client_err)))
}
fn storage_keys_paged(
&self,
block: Option<Block::Hash>,
prefix: Option<StorageKey>,
count: u32,
start_key: Option<StorageKey>,
) -> FutureResult<Vec<StorageKey>> {
Box::new(result(
self.block_or_best(block)
.and_then(|block|
self.client.storage_keys_iter(
&BlockId::Hash(block), prefix.as_ref(), start_key.as_ref()
)
)
.map(|v| v.take(count as usize).collect())
.map_err(client_err)))
}
fn storage(
&self,
block: Option<Block::Hash>,
@@ -199,6 +199,16 @@ impl<Block, F, B, E, RA> StateBackend<B, E, Block, RA> for LightState<Block, F,
Box::new(result(Err(client_err(ClientError::NotAvailableOnLightClient))))
}
fn storage_keys_paged(
&self,
_block: Option<Block::Hash>,
_prefix: Option<StorageKey>,
_count: u32,
_start_key: Option<StorageKey>,
) -> FutureResult<Vec<StorageKey>> {
Box::new(result(Err(client_err(ClientError::NotAvailableOnLightClient))))
}
fn storage(
&self,
block: Option<Block::Hash>,