Skip to content
Snippets Groups Projects
Commit 52d0173e authored by Yuanchao Sun's avatar Yuanchao Sun Committed by GitHub
Browse files

Add RPC function state_getProof, resolves #1110 (#5649)


* Add RPC function state_getProof, resolves #1110

* Apply suggestions from code review

* Update client/rpc/src/state/state_full.rs

Co-Authored-By: default avatarBastian Köcher <bkchr@users.noreply.github.com>

* Update Cargo.lock

* Make block hash optional

* Wrap StorageProof as Bytes

* Add struct ReadProof

* Fix typo

Co-authored-by: default avatarBastian Köcher <bkchr@users.noreply.github.com>
parent 0ce9657d
No related merge requests found
// 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 <http://www.gnu.org/licenses/>.
//! 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<Hash> {
/// 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<Bytes>,
}
......@@ -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<Hash> {
at: Option<Hash>,
) -> FutureResult<Vec<StorageChangeSet<Hash>>>;
/// Returns proof of storage entries at a specific block's state.
#[rpc(name = "state_getReadProof")]
fn read_proof(&self, keys: Vec<StorageKey>, hash: Option<Hash>) -> FutureResult<ReadProof<Hash>>;
/// New runtime version subscription
#[pubsub(
subscription = "state_runtimeVersion",
......
......@@ -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<Block: BlockT, Client>: Send + Sync + 'static
at: Option<Block::Hash>
) -> FutureResult<Vec<StorageChangeSet<Block::Hash>>>;
/// Returns proof of storage entries at a specific block's state.
fn read_proof(
&self,
block: Option<Block::Hash>,
keys: Vec<StorageKey>,
) -> FutureResult<ReadProof<Block::Hash>>;
/// New runtime version subscription
fn subscribe_runtime_version(
&self,
......@@ -166,7 +173,7 @@ pub fn new_full<BE, Block: BlockT, Client>(
where
Block: BlockT + 'static,
BE: Backend<Block> + 'static,
Client: ExecutorProvider<Block> + StorageProvider<Block, BE> + HeaderBackend<Block>
Client: ExecutorProvider<Block> + StorageProvider<Block, BE> + ProofProvider<Block> + HeaderBackend<Block>
+ HeaderMetadata<Block, Error = sp_blockchain::Error> + BlockchainEvents<Block>
+ CallApiAt<Block, Error = sp_blockchain::Error>
+ ProvideRuntimeApi<Block> + Send + Sync + 'static,
......@@ -294,6 +301,10 @@ impl<Block, Client> StateApi<Block::Hash> for State<Block, Client>
self.backend.query_storage_at(keys, at)
}
fn read_proof(&self, keys: Vec<StorageKey>, block: Option<Block::Hash>) -> FutureResult<ReadProof<Block::Hash>> {
self.backend.read_proof(block, keys)
}
fn subscribe_storage(
&self,
meta: Self::Metadata,
......
......@@ -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<Block: BlockT> {
......@@ -219,7 +219,7 @@ impl<BE, Block: BlockT, Client> FullState<BE, Block, Client>
impl<BE, Block, Client> StateBackend<Block, Client> for FullState<BE, Block, Client> where
Block: BlockT + 'static,
BE: Backend<Block> + 'static,
Client: ExecutorProvider<Block> + StorageProvider<Block, BE> + HeaderBackend<Block>
Client: ExecutorProvider<Block> + StorageProvider<Block, BE> + ProofProvider<Block> + HeaderBackend<Block>
+ HeaderMetadata<Block, Error = sp_blockchain::Error> + BlockchainEvents<Block>
+ CallApiAt<Block, Error = sp_blockchain::Error> + ProvideRuntimeApi<Block>
+ Send + Sync + 'static,
......@@ -351,6 +351,26 @@ impl<BE, Block, Client> StateBackend<Block, Client> for FullState<BE, Block, Cli
self.query_storage(at, Some(at), keys)
}
fn read_proof(
&self,
block: Option<Block::Hash>,
keys: Vec<StorageKey>,
) -> FutureResult<ReadProof<Block::Hash>> {
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,
......
......@@ -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<Block, F, Client> StateBackend<Block, Client> for LightState<Block, F, Clie
Box::new(result(Err(client_err(ClientError::NotAvailableOnLightClient))))
}
fn read_proof(
&self,
_block: Option<Block::Hash>,
_keys: Vec<StorageKey>,
) -> FutureResult<ReadProof<Block::Hash>> {
Box::new(result(Err(client_err(ClientError::NotAvailableOnLightClient))))
}
fn subscribe_storage(
&self,
_meta: crate::metadata::Metadata,
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment