diff --git a/substrate/client/rpc-api/src/state/helpers.rs b/substrate/client/rpc-api/src/state/helpers.rs
new file mode 100644
index 0000000000..516b6c80c4
--- /dev/null
+++ b/substrate/client/rpc-api/src/state/helpers.rs
@@ -0,0 +1,30 @@
+// Copyright 2020 Parity Technologies (UK) Ltd.
+// This file is part of Substrate.
+
+// Substrate is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Substrate is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Substrate. If not, see .
+
+//! Substrate state API helpers.
+
+use sp_core::Bytes;
+use serde::{Serialize, Deserialize};
+
+/// ReadProof struct returned by the RPC
+#[derive(Debug, PartialEq, Serialize, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct ReadProof {
+ /// Block hash used to generate the proof
+ pub at: Hash,
+ /// A proof used to prove that storage entries are included in the storage trie
+ pub proof: Vec,
+}
diff --git a/substrate/client/rpc-api/src/state/mod.rs b/substrate/client/rpc-api/src/state/mod.rs
index 243a33c18d..3d38a16eb4 100644
--- a/substrate/client/rpc-api/src/state/mod.rs
+++ b/substrate/client/rpc-api/src/state/mod.rs
@@ -17,6 +17,7 @@
//! Substrate state API.
pub mod error;
+pub mod helpers;
use jsonrpc_core::Result as RpcResult;
use jsonrpc_core::futures::Future;
@@ -28,6 +29,7 @@ use sp_version::RuntimeVersion;
use self::error::FutureResult;
pub use self::gen_client::Client as StateClient;
+pub use self::helpers::ReadProof;
/// Substrate state API
#[rpc]
@@ -100,6 +102,10 @@ pub trait StateApi {
at: Option,
) -> FutureResult>>;
+ /// Returns proof of storage entries at a specific block's state.
+ #[rpc(name = "state_getReadProof")]
+ fn read_proof(&self, keys: Vec, hash: Option) -> FutureResult>;
+
/// New runtime version subscription
#[pubsub(
subscription = "state_runtimeVersion",
diff --git a/substrate/client/rpc/src/state/mod.rs b/substrate/client/rpc/src/state/mod.rs
index e696282433..b3ac367422 100644
--- a/substrate/client/rpc/src/state/mod.rs
+++ b/substrate/client/rpc/src/state/mod.rs
@@ -26,7 +26,7 @@ use std::sync::Arc;
use jsonrpc_pubsub::{typed::Subscriber, SubscriptionId};
use rpc::{Result as RpcResult, futures::{Future, future::result}};
-use sc_rpc_api::Subscriptions;
+use sc_rpc_api::{Subscriptions, state::ReadProof};
use sc_client::{light::{blockchain::RemoteBlockchain, fetcher::Fetcher}};
use sp_core::{Bytes, storage::{StorageKey, PrefixedStorageKey, StorageData, StorageChangeSet}};
use sp_version::RuntimeVersion;
@@ -38,7 +38,7 @@ use self::error::{Error, FutureResult};
pub use sc_rpc_api::state::*;
pub use sc_rpc_api::child_state::*;
-use sc_client_api::{ExecutorProvider, StorageProvider, BlockchainEvents, Backend};
+use sc_client_api::{ExecutorProvider, StorageProvider, BlockchainEvents, Backend, ProofProvider};
use sp_blockchain::{HeaderMetadata, HeaderBackend};
const STORAGE_KEYS_PAGED_MAX_COUNT: u32 = 1000;
@@ -128,6 +128,13 @@ pub trait StateBackend: Send + Sync + 'static
at: Option
) -> FutureResult>>;
+ /// Returns proof of storage entries at a specific block's state.
+ fn read_proof(
+ &self,
+ block: Option,
+ keys: Vec,
+ ) -> FutureResult>;
+
/// New runtime version subscription
fn subscribe_runtime_version(
&self,
@@ -166,7 +173,7 @@ pub fn new_full(
where
Block: BlockT + 'static,
BE: Backend + 'static,
- Client: ExecutorProvider + StorageProvider + HeaderBackend
+ Client: ExecutorProvider + StorageProvider + ProofProvider + HeaderBackend
+ HeaderMetadata + BlockchainEvents
+ CallApiAt
+ ProvideRuntimeApi + Send + Sync + 'static,
@@ -294,6 +301,10 @@ impl StateApi for State
self.backend.query_storage_at(keys, at)
}
+ fn read_proof(&self, keys: Vec, block: Option) -> FutureResult> {
+ self.backend.read_proof(block, keys)
+ }
+
fn subscribe_storage(
&self,
meta: Self::Metadata,
diff --git a/substrate/client/rpc/src/state/state_full.rs b/substrate/client/rpc/src/state/state_full.rs
index a9767c34fc..4546692b7b 100644
--- a/substrate/client/rpc/src/state/state_full.rs
+++ b/substrate/client/rpc/src/state/state_full.rs
@@ -24,7 +24,7 @@ use log::warn;
use jsonrpc_pubsub::{typed::Subscriber, SubscriptionId};
use rpc::{Result as RpcResult, futures::{stream, Future, Sink, Stream, future::result}};
-use sc_rpc_api::Subscriptions;
+use sc_rpc_api::{Subscriptions, state::ReadProof};
use sc_client_api::backend::Backend;
use sp_blockchain::{Result as ClientResult, Error as ClientError, HeaderMetadata, CachedHeaderMetadata, HeaderBackend};
use sc_client::BlockchainEvents;
@@ -41,7 +41,7 @@ use sp_api::{Metadata, ProvideRuntimeApi, CallApiAt};
use super::{StateBackend, ChildStateBackend, error::{FutureResult, Error, Result}, client_err};
use std::marker::PhantomData;
-use sc_client_api::{CallExecutor, StorageProvider, ExecutorProvider};
+use sc_client_api::{CallExecutor, StorageProvider, ExecutorProvider, ProofProvider};
/// Ranges to query in state_queryStorage.
struct QueryStorageRange {
@@ -219,7 +219,7 @@ impl FullState
impl StateBackend for FullState where
Block: BlockT + 'static,
BE: Backend + 'static,
- Client: ExecutorProvider + StorageProvider + HeaderBackend
+ Client: ExecutorProvider + StorageProvider + ProofProvider + HeaderBackend
+ HeaderMetadata + BlockchainEvents
+ CallApiAt + ProvideRuntimeApi
+ Send + Sync + 'static,
@@ -351,6 +351,26 @@ impl StateBackend for FullState,
+ keys: Vec,
+ ) -> FutureResult> {
+ Box::new(result(
+ self.block_or_best(block)
+ .and_then(|block| {
+ self.client
+ .read_proof(
+ &BlockId::Hash(block),
+ &mut keys.iter().map(|key| key.0.as_ref()),
+ )
+ .map(|proof| proof.iter_nodes().map(|node| node.into()).collect())
+ .map(|proof| ReadProof { at: block, proof })
+ })
+ .map_err(client_err),
+ ))
+ }
+
fn subscribe_runtime_version(
&self,
_meta: crate::metadata::Metadata,
diff --git a/substrate/client/rpc/src/state/state_light.rs b/substrate/client/rpc/src/state/state_light.rs
index 27adbcd691..10adab9cc3 100644
--- a/substrate/client/rpc/src/state/state_light.rs
+++ b/substrate/client/rpc/src/state/state_light.rs
@@ -38,7 +38,7 @@ use rpc::{
futures::stream::Stream,
};
-use sc_rpc_api::Subscriptions;
+use sc_rpc_api::{Subscriptions, state::ReadProof};
use sp_blockchain::{Error as ClientError, HeaderBackend};
use sc_client::{
BlockchainEvents,
@@ -279,6 +279,14 @@ impl StateBackend for LightState,
+ _keys: Vec,
+ ) -> FutureResult> {
+ Box::new(result(Err(client_err(ClientError::NotAvailableOnLightClient))))
+ }
+
fn subscribe_storage(
&self,
_meta: crate::metadata::Metadata,