Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Adds state_queryStorageAt #5362

Merged
merged 4 commits into from
Mar 26, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions client/rpc-api/src/state/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,14 @@ pub trait StateApi<Hash> {
hash: Option<Hash>
) -> FutureResult<Vec<StorageChangeSet<Hash>>>;

/// Query storage entries (by key) starting at block hash given as the second parameter.
#[rpc(name = "state_queryStorageAt")]
fn query_storage_at(
&self,
keys: Vec<StorageKey>,
at: Option<Hash>,
) -> FutureResult<Vec<StorageChangeSet<Hash>>>;

/// New runtime version subscription
#[pubsub(
subscription = "state_runtimeVersion",
Expand Down
15 changes: 15 additions & 0 deletions client/rpc/src/state/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,13 @@ pub trait StateBackend<Block: BlockT, Client>: Send + Sync + 'static
keys: Vec<StorageKey>,
) -> FutureResult<Vec<StorageChangeSet<Block::Hash>>>;

/// Query storage entries (by key) starting at block hash given as the second parameter.
fn query_storage_at(
&self,
keys: Vec<StorageKey>,
at: Option<Block::Hash>
) -> FutureResult<Vec<StorageChangeSet<Block::Hash>>>;

/// New runtime version subscription
fn subscribe_runtime_version(
&self,
Expand Down Expand Up @@ -357,6 +364,14 @@ impl<Block, Client> StateApi<Block::Hash> for State<Block, Client>
self.backend.query_storage(from, to, keys)
}

fn query_storage_at(
&self,
keys: Vec<StorageKey>,
at: Option<Block::Hash>
) -> FutureResult<Vec<StorageChangeSet<Block::Hash>>> {
self.backend.query_storage_at(keys, at)
}

fn subscribe_storage(
&self,
meta: Self::Metadata,
Expand Down
20 changes: 16 additions & 4 deletions client/rpc/src/state/state_full.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ use sp_core::{
};
use sp_version::RuntimeVersion;
use sp_runtime::{
generic::BlockId, traits::{Block as BlockT, NumberFor, SaturatedConversion},
generic::BlockId, traits::{Block as BlockT, NumberFor, SaturatedConversion, CheckedSub},
};

use sp_api::{Metadata, ProvideRuntimeApi, CallApiAt};
Expand Down Expand Up @@ -94,8 +94,8 @@ impl<BE, Block: BlockT, Client> FullState<BE, Block, Client>
let from_meta = self.client.header_metadata(from).map_err(invalid_block_err)?;
let to_meta = self.client.header_metadata(to).map_err(invalid_block_err)?;

if from_meta.number >= to_meta.number {
return Err(invalid_block_range(&from_meta, &to_meta, "from number >= to number".to_owned()))
if from_meta.number > to_meta.number {
return Err(invalid_block_range(&from_meta, &to_meta, "from number > to number".to_owned()))
}

// check if we can get from `to` to `from` by going through parent_hashes.
Expand All @@ -122,7 +122,10 @@ impl<BE, Block: BlockT, Client> FullState<BE, Block, Client>
.max_key_changes_range(from_number, BlockId::Hash(to_meta.hash))
.map_err(client_err)?;
let filtered_range_begin = changes_trie_range
.map(|(begin, _)| (begin - from_number).saturated_into::<usize>());
.and_then(|(begin, _)| {
// avoids a corner case where begin < from_number (happens when querying genesis)
begin.checked_sub(&from_number).map(|x| x.saturated_into::<usize>())
});
let (unfiltered_range, filtered_range) = split_range(hashes.len(), filtered_range_begin);

Ok(QueryStorageRange {
Expand Down Expand Up @@ -398,6 +401,15 @@ impl<BE, Block, Client> StateBackend<Block, Client> for FullState<BE, Block, Cli
Box::new(result(call_fn()))
}

fn query_storage_at(
&self,
keys: Vec<StorageKey>,
at: Option<Block::Hash>
) -> FutureResult<Vec<StorageChangeSet<Block::Hash>>> {
let at = at.unwrap_or_else(|| self.client.info().best_hash);
self.query_storage(at, Some(at), keys)
}

fn subscribe_runtime_version(
&self,
_meta: crate::metadata::Metadata,
Expand Down
8 changes: 8 additions & 0 deletions client/rpc/src/state/state_light.rs
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,14 @@ impl<Block, F, Client> StateBackend<Block, Client> for LightState<Block, F, Clie
Box::new(result(Err(client_err(ClientError::NotAvailableOnLightClient))))
}

fn query_storage_at(
&self,
_keys: Vec<StorageKey>,
_at: Option<Block::Hash>
) -> FutureResult<Vec<StorageChangeSet<Block::Hash>>> {
Box::new(result(Err(client_err(ClientError::NotAvailableOnLightClient))))
}

fn subscribe_storage(
&self,
_meta: crate::metadata::Metadata,
Expand Down
47 changes: 41 additions & 6 deletions client/rpc/src/state/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ use substrate_test_runtime_client::{
sp_consensus::BlockOrigin,
runtime,
};
use sp_runtime::generic::BlockId;

const CHILD_INFO: ChildInfo<'static> = ChildInfo::new_default(b"unique_id");

Expand Down Expand Up @@ -212,7 +213,7 @@ fn should_send_initial_storage_changes_and_notifications() {

#[test]
fn should_query_storage() {
fn run_tests(mut client: Arc<TestClient>) {
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())));

Expand All @@ -237,6 +238,13 @@ fn should_query_storage() {
let block2_hash = add_block(1);
let genesis_hash = client.genesis_hash();

if has_changes_trie_config {
assert_eq!(
client.max_key_changes_range(1, BlockId::Hash(block1_hash)).unwrap(),
Some((0, BlockId::Hash(block1_hash))),
);
}

Comment on lines +241 to +247
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bkchr already added.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh nice! Ty!

let mut expected = vec![
StorageChangeSet {
block: genesis_hash,
Expand Down Expand Up @@ -306,7 +314,7 @@ fn should_query_storage() {
Err(Error::InvalidBlockRange {
from: format!("1 ({:?})", block1_hash),
to: format!("0 ({:?})", genesis_hash),
details: "from number >= to number".to_owned(),
details: "from number > to number".to_owned(),
}).map_err(|e| e.to_string())
);

Expand Down Expand Up @@ -376,12 +384,39 @@ fn should_query_storage() {
details: format!("UnknownBlock: header not found in db: {}", random_hash1),
}).map_err(|e| e.to_string()),
);

// single block range
let result = api.query_storage_at(
keys.clone(),
Some(block1_hash),
);

assert_eq!(
result.wait().unwrap(),
vec![
StorageChangeSet {
block: block1_hash,
changes: vec![
(StorageKey(vec![1_u8]), None),
(StorageKey(vec![2_u8]), Some(StorageData(vec![2_u8]))),
(StorageKey(vec![3_u8]), Some(StorageData(vec![3_u8]))),
(StorageKey(vec![4_u8]), None),
(StorageKey(vec![5_u8]), Some(StorageData(vec![0_u8]))),
]
}
]
);
}

run_tests(Arc::new(substrate_test_runtime_client::new()));
run_tests(Arc::new(TestClientBuilder::new()
.changes_trie_config(Some(ChangesTrieConfiguration::new(4, 2)))
.build()));
run_tests(Arc::new(substrate_test_runtime_client::new()), false);
run_tests(
Arc::new(
TestClientBuilder::new()
.changes_trie_config(Some(ChangesTrieConfiguration::new(4, 2)))
.build(),
),
true,
);
}

#[test]
Expand Down