diff --git a/Cargo.lock b/Cargo.lock index 4f42fa17cd452..9a380eaac1876 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3569,6 +3569,7 @@ dependencies = [ "sc-basic-authorship", "sc-cli", "sc-client", + "sc-client-api", "sc-consensus-aura", "sc-executor", "sc-finality-grandpa", @@ -5777,6 +5778,7 @@ dependencies = [ "sp-runtime", "sp-state-machine", "sp-std", + "sp-storage", "sp-test-primitives", "sp-transaction-pool", "sp-trie", diff --git a/bin/node-template/node/Cargo.toml b/bin/node-template/node/Cargo.toml index bccd0576dfa45..1e8c3fad2e3c0 100644 --- a/bin/node-template/node/Cargo.toml +++ b/bin/node-template/node/Cargo.toml @@ -30,6 +30,7 @@ sp-consensus = { version = "0.8.0-alpha.2", path = "../../../primitives/consensu grandpa = { version = "0.8.0-alpha.2", package = "sc-finality-grandpa", path = "../../../client/finality-grandpa" } grandpa-primitives = { version = "2.0.0-alpha.2", package = "sp-finality-grandpa", path = "../../../primitives/finality-grandpa" } sc-client = { version = "0.8.0-alpha.2", path = "../../../client/" } +sc-client-api = { version = "2.0.0-alpha.2", path = "../../../client/api" } sp-runtime = { version = "2.0.0-alpha.2", path = "../../../primitives/runtime" } sc-basic-authorship = { path = "../../../client/basic-authorship" , version = "0.8.0-alpha.2"} diff --git a/bin/node-template/node/src/service.rs b/bin/node-template/node/src/service.rs index fe1b3af4eb4ab..f289ff58549db 100644 --- a/bin/node-template/node/src/service.rs +++ b/bin/node-template/node/src/service.rs @@ -3,13 +3,14 @@ use std::sync::Arc; use std::time::Duration; use sc_client::LongestChain; +use sc_client_api::ExecutorProvider; use node_template_runtime::{self, GenesisConfig, opaque::Block, RuntimeApi}; use sc_service::{error::{Error as ServiceError}, AbstractService, Configuration, ServiceBuilder}; use sp_inherents::InherentDataProviders; use sc_executor::native_executor_instance; pub use sc_executor::NativeExecutor; use sp_consensus_aura::sr25519::{AuthorityPair as AuraPair}; -use grandpa::{self, FinalityProofProvider as GrandpaFinalityProofProvider}; +use grandpa::{self, FinalityProofProvider as GrandpaFinalityProofProvider, StorageAndProofProvider}; // Our native executor instance. native_executor_instance!( @@ -24,6 +25,7 @@ native_executor_instance!( /// be able to perform chain operations. macro_rules! new_full_start { ($config:expr) => {{ + use std::sync::Arc; let mut import_setup = None; let inherent_data_providers = sp_inherents::InherentDataProviders::new(); @@ -42,7 +44,7 @@ macro_rules! new_full_start { .ok_or_else(|| sc_service::Error::SelectChainRequired)?; let (grandpa_block_import, grandpa_link) = - grandpa::block_import(client.clone(), &*client, select_chain)?; + grandpa::block_import(client.clone(), &(client.clone() as Arc<_>), select_chain)?; let aura_block_import = sc_consensus_aura::AuraBlockImport::<_, _, _, AuraPair>::new( grandpa_block_import.clone(), client.clone(), @@ -87,9 +89,11 @@ pub fn new_full(config: Configuration) .expect("Link Half and Block Import are present for Full Services or setup failed before. qed"); let service = builder - .with_finality_proof_provider(|client, backend| - Ok(Arc::new(GrandpaFinalityProofProvider::new(backend, client)) as _) - )? + .with_finality_proof_provider(|client, backend| { + // GenesisAuthoritySetProvider is implemented for StorageAndProofProvider + let provider = client as Arc>; + Ok(Arc::new(GrandpaFinalityProofProvider::new(backend, provider)) as _) + })? .build()?; if participates_in_consensus { @@ -201,7 +205,10 @@ pub fn new_light(config: Configuration) .map(|fetcher| fetcher.checker().clone()) .ok_or_else(|| "Trying to start light import queue without active fetch checker")?; let grandpa_block_import = grandpa::light_block_import( - client.clone(), backend, &*client.clone(), Arc::new(fetch_checker), + client.clone(), + backend, + &(client.clone() as Arc<_>), + Arc::new(fetch_checker), )?; let finality_proof_import = grandpa_block_import.clone(); let finality_proof_request_builder = @@ -218,8 +225,10 @@ pub fn new_light(config: Configuration) Ok((import_queue, finality_proof_request_builder)) })? - .with_finality_proof_provider(|client, backend| - Ok(Arc::new(GrandpaFinalityProofProvider::new(backend, client)) as _) - )? + .with_finality_proof_provider(|client, backend| { + // GenesisAuthoritySetProvider is implemented for StorageAndProofProvider + let provider = client as Arc>; + Ok(Arc::new(GrandpaFinalityProofProvider::new(backend, provider)) as _) + })? .build() } diff --git a/bin/node/cli/src/service.rs b/bin/node/cli/src/service.rs index ca7bd43161858..332c47ea132ea 100644 --- a/bin/node/cli/src/service.rs +++ b/bin/node/cli/src/service.rs @@ -22,7 +22,7 @@ use std::sync::Arc; use sc_consensus_babe; use sc_client::{self, LongestChain}; -use grandpa::{self, FinalityProofProvider as GrandpaFinalityProofProvider}; +use grandpa::{self, FinalityProofProvider as GrandpaFinalityProofProvider, StorageAndProofProvider}; use node_executor; use node_primitives::Block; use node_runtime::{GenesisConfig, RuntimeApi}; @@ -45,6 +45,7 @@ use sc_offchain::OffchainWorkers; /// be able to perform chain operations. macro_rules! new_full_start { ($config:expr) => {{ + use std::sync::Arc; type RpcExtension = jsonrpc_core::IoHandler; let mut import_setup = None; let inherent_data_providers = sp_inherents::InherentDataProviders::new(); @@ -64,7 +65,7 @@ macro_rules! new_full_start { .ok_or_else(|| sc_service::Error::SelectChainRequired)?; let (grandpa_block_import, grandpa_link) = grandpa::block_import( client.clone(), - &*client, + &(client.clone() as Arc<_>), select_chain, )?; let justification_import = grandpa_block_import.clone(); @@ -116,6 +117,7 @@ macro_rules! new_full { ($config:expr, $with_startup_data: expr) => {{ use futures::prelude::*; use sc_network::Event; + use sc_client_api::ExecutorProvider; let ( is_authority, @@ -139,9 +141,11 @@ macro_rules! new_full { let (builder, mut import_setup, inherent_data_providers) = new_full_start!($config); let service = builder - .with_finality_proof_provider(|client, backend| - Ok(Arc::new(grandpa::FinalityProofProvider::new(backend, client)) as _) - )? + .with_finality_proof_provider(|client, backend| { + // GenesisAuthoritySetProvider is implemented for StorageAndProofProvider + let provider = client as Arc>; + Ok(Arc::new(grandpa::FinalityProofProvider::new(backend, provider)) as _) + })? .build()?; let (block_import, grandpa_link, babe_link) = import_setup.take() @@ -255,8 +259,7 @@ type ConcreteBlock = node_primitives::Block; type ConcreteClient = Client< Backend, - LocalCallExecutor, - NativeExecutor>, + LocalCallExecutor, NativeExecutor>, ConcreteBlock, node_runtime::RuntimeApi >; @@ -317,7 +320,7 @@ pub fn new_light(config: NodeConfiguration) let grandpa_block_import = grandpa::light_block_import( client.clone(), backend, - &*client, + &(client.clone() as Arc<_>), Arc::new(fetch_checker), )?; @@ -342,9 +345,11 @@ pub fn new_light(config: NodeConfiguration) Ok((import_queue, finality_proof_request_builder)) })? - .with_finality_proof_provider(|client, backend| - Ok(Arc::new(GrandpaFinalityProofProvider::new(backend, client)) as _) - )? + .with_finality_proof_provider(|client, backend| { + // GenesisAuthoritySetProvider is implemented for StorageAndProofProvider + let provider = client as Arc>; + Ok(Arc::new(GrandpaFinalityProofProvider::new(backend, provider)) as _) + })? .with_rpc_extensions(|builder,| -> Result { diff --git a/client/api/Cargo.toml b/client/api/Cargo.toml index 025689105473f..7ceb12eaf60bb 100644 --- a/client/api/Cargo.toml +++ b/client/api/Cargo.toml @@ -34,6 +34,7 @@ sp-runtime = { version = "2.0.0-alpha.2", default-features = false, path = "../. sp-state-machine = { version = "0.8.0-alpha.2", path = "../../primitives/state-machine" } sc-telemetry = { version = "2.0.0-alpha.2", path = "../telemetry" } sp-trie = { version = "2.0.0-alpha.2", path = "../../primitives/trie" } +sp-storage = { version = "2.0.0-alpha.2", path = "../../primitives/storage" } sp-transaction-pool = { version = "2.0.0-alpha.2", path = "../../primitives/transaction-pool" } [dev-dependencies] diff --git a/client/api/src/backend.rs b/client/api/src/backend.rs index 1f76aa8c1aff2..808ca7a870ac7 100644 --- a/client/api/src/backend.rs +++ b/client/api/src/backend.rs @@ -26,6 +26,7 @@ use sp_state_machine::{ ChangesTrieState, ChangesTrieStorage as StateChangesTrieStorage, ChangesTrieTransaction, StorageCollection, ChildStorageCollection, }; +use sp_storage::{StorageData, StorageKey, ChildInfo}; use crate::{ blockchain::{ Backend as BlockchainBackend, well_known_cache_keys @@ -38,6 +39,7 @@ use sp_consensus::BlockOrigin; use parking_lot::RwLock; pub use sp_state_machine::Backend as StateBackend; +use std::marker::PhantomData; /// Extracts the state backend type for the given backend. pub type StateBackendFor = >::State; @@ -237,6 +239,123 @@ pub trait AuxStore { fn get_aux(&self, key: &[u8]) -> sp_blockchain::Result>>; } +/// An `Iterator` that iterates keys in a given block under a prefix. +pub struct KeyIterator<'a, State, Block> { + state: State, + prefix: Option<&'a StorageKey>, + current_key: Vec, + _phantom: PhantomData, +} + +impl <'a, State, Block> KeyIterator<'a, State, Block> { + /// create a KeyIterator instance + pub fn new(state: State, prefix: Option<&'a StorageKey>, current_key: Vec) -> Self { + Self { + state, + prefix, + current_key, + _phantom: PhantomData, + } + } +} + +impl<'a, State, Block> Iterator for KeyIterator<'a, State, Block> where + Block: BlockT, + State: StateBackend>, +{ + type Item = StorageKey; + + fn next(&mut self) -> Option { + let next_key = self.state + .next_storage_key(&self.current_key) + .ok() + .flatten()?; + // this terminates the iterator the first time it fails. + if let Some(prefix) = self.prefix { + if !next_key.starts_with(&prefix.0[..]) { + return None; + } + } + self.current_key = next_key.clone(); + Some(StorageKey(next_key)) + } +} +/// Provides acess to storage primitives +pub trait StorageProvider> { + /// Given a `BlockId` and a key, return the value under the key in that block. + fn storage(&self, id: &BlockId, key: &StorageKey) -> sp_blockchain::Result>; + + /// Given a `BlockId` and a key prefix, return the matching storage keys in that block. + fn storage_keys(&self, id: &BlockId, key_prefix: &StorageKey) -> sp_blockchain::Result>; + + /// Given a `BlockId` and a key, return the value under the hash in that block. + fn storage_hash(&self, id: &BlockId, key: &StorageKey) -> sp_blockchain::Result>; + + /// Given a `BlockId` and a key prefix, return the matching child storage keys and values in that block. + fn storage_pairs( + &self, + id: &BlockId, + key_prefix: &StorageKey + ) -> sp_blockchain::Result>; + + /// Given a `BlockId` and a key prefix, return a `KeyIterator` iterates matching storage keys in that block. + fn storage_keys_iter<'a>( + &self, + id: &BlockId, + prefix: Option<&'a StorageKey>, + start_key: Option<&StorageKey> + ) -> sp_blockchain::Result>; + + /// Given a `BlockId`, a key and a child storage key, return the value under the key in that block. + fn child_storage( + &self, + id: &BlockId, + storage_key: &StorageKey, + child_info: ChildInfo, + key: &StorageKey + ) -> sp_blockchain::Result>; + + /// Given a `BlockId`, a key prefix, and a child storage key, return the matching child storage keys. + fn child_storage_keys( + &self, + id: &BlockId, + child_storage_key: &StorageKey, + child_info: ChildInfo, + key_prefix: &StorageKey + ) -> sp_blockchain::Result>; + + /// Given a `BlockId`, a key and a child storage key, return the hash under the key in that block. + fn child_storage_hash( + &self, + id: &BlockId, + storage_key: &StorageKey, + child_info: ChildInfo, + key: &StorageKey + ) -> sp_blockchain::Result>; + + /// Get longest range within [first; last] that is possible to use in `key_changes` + /// and `key_changes_proof` calls. + /// Range could be shortened from the beginning if some changes tries have been pruned. + /// Returns Ok(None) if changes tries are not supported. + fn max_key_changes_range( + &self, + first: NumberFor, + last: BlockId, + ) -> sp_blockchain::Result, BlockId)>>; + + /// Get pairs of (block, extrinsic) where key has been changed at given blocks range. + /// Works only for runtimes that are supporting changes tries. + /// + /// Changes are returned in descending order (i.e. last block comes first). + fn key_changes( + &self, + first: NumberFor, + last: BlockId, + storage_key: Option<&StorageKey>, + key: &StorageKey + ) -> sp_blockchain::Result, u32)>>; +} + /// Client backend. /// /// Manages the data layer. diff --git a/client/api/src/call_executor.rs b/client/api/src/call_executor.rs index 1a7b53d541542..f39d797157896 100644 --- a/client/api/src/call_executor.rs +++ b/client/api/src/call_executor.rs @@ -29,6 +29,18 @@ use sp_externalities::Extensions; use sp_core::NativeOrEncoded; use sp_api::{ProofRecorder, InitializeBlock, StorageTransactionCache}; +use crate::execution_extensions::ExecutionExtensions; + +/// Executor Provider +pub trait ExecutorProvider { + /// executor instance + type Executor: CallExecutor; + /// Get call executor reference. + fn executor(&self) -> &Self::Executor; + + /// Get a reference to the execution extensions. + fn execution_extensions(&self) -> &ExecutionExtensions; +} /// Method call executor. pub trait CallExecutor { diff --git a/client/api/src/client.rs b/client/api/src/client.rs index 4980015568be9..22503732be4e9 100644 --- a/client/api/src/client.rs +++ b/client/api/src/client.rs @@ -21,7 +21,7 @@ use futures::channel::mpsc; use sp_core::storage::StorageKey; use sp_runtime::{ traits::{Block as BlockT, NumberFor}, - generic::BlockId + generic::{BlockId, SignedBlock} }; use sp_consensus::BlockOrigin; @@ -76,9 +76,13 @@ pub trait BlockchainEvents { /// Fetch block body by ID. pub trait BlockBody { /// Get block body by ID. Returns `None` if the body is not stored. - fn block_body(&self, + fn block_body( + &self, id: &BlockId ) -> sp_blockchain::Result::Extrinsic>>>; + + /// Get full block by id. + fn block(&self, id: &BlockId) -> sp_blockchain::Result>>; } /// Provide a list of potential uncle headers for a given block. diff --git a/client/api/src/lib.rs b/client/api/src/lib.rs index 69d0c94ac2b8b..66f51e75c7937 100644 --- a/client/api/src/lib.rs +++ b/client/api/src/lib.rs @@ -23,6 +23,7 @@ pub mod client; pub mod execution_extensions; pub mod light; pub mod notifications; +pub mod proof_provider; pub use sp_blockchain as blockchain; pub use backend::*; @@ -31,6 +32,7 @@ pub use call_executor::*; pub use client::*; pub use light::*; pub use notifications::*; +pub use proof_provider::*; pub use sp_state_machine::{StorageProof, ExecutionStrategy}; diff --git a/client/api/src/proof_provider.rs b/client/api/src/proof_provider.rs new file mode 100644 index 0000000000000..2d9876f7ad278 --- /dev/null +++ b/client/api/src/proof_provider.rs @@ -0,0 +1,71 @@ +// Copyright 2017-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 . +//! Proof utilities +use sp_runtime::{ + generic::BlockId, + traits::{Block as BlockT}, +}; +use crate::{StorageProof, ChangesProof}; +use sp_storage::{ChildInfo, StorageKey}; + +/// Interface for providing block proving utilities. +pub trait ProofProvider { + /// Reads storage value at a given block + key, returning read proof. + fn read_proof( + &self, + id: &BlockId, + keys: &mut dyn Iterator, + ) -> sp_blockchain::Result; + + /// Reads child storage value at a given block + storage_key + key, returning + /// read proof. + fn read_child_proof( + &self, + id: &BlockId, + storage_key: &[u8], + child_info: ChildInfo, + keys: &mut dyn Iterator, + ) -> sp_blockchain::Result; + + /// Execute a call to a contract on top of state in a block of given hash + /// AND returning execution proof. + /// + /// No changes are made. + fn execution_proof( + &self, + id: &BlockId, + method: &str, + call_data: &[u8], + ) -> sp_blockchain::Result<(Vec, StorageProof)>; + /// Reads given header and generates CHT-based header proof. + fn header_proof(&self, id: &BlockId) -> sp_blockchain::Result<(Block::Header, StorageProof)>; + + /// Get proof for computation of (block, extrinsic) pairs where key has been changed at given blocks range. + /// `min` is the hash of the first block, which changes trie root is known to the requester - when we're using + /// changes tries from ascendants of this block, we should provide proofs for changes tries roots + /// `max` is the hash of the last block known to the requester - we can't use changes tries from descendants + /// of this block. + /// Works only for runtimes that are supporting changes tries. + fn key_changes_proof( + &self, + first: Block::Hash, + last: Block::Hash, + min: Block::Hash, + max: Block::Hash, + storage_key: Option<&StorageKey>, + key: &StorageKey, + ) -> sp_blockchain::Result>; +} diff --git a/client/finality-grandpa/src/environment.rs b/client/finality-grandpa/src/environment.rs index 21a44c32dc9ea..a0f37f20cb390 100644 --- a/client/finality-grandpa/src/environment.rs +++ b/client/finality-grandpa/src/environment.rs @@ -28,10 +28,7 @@ use parking_lot::RwLock; use sp_blockchain::{HeaderBackend, Error as ClientError, HeaderMetadata}; use std::marker::PhantomData; -use sc_client_api::{ - backend::Backend, - utils::is_descendent_of, -}; +use sc_client_api::{backend::Backend, utils::is_descendent_of}; use sc_client::apply_aux; use finality_grandpa::{ BlockNumberOps, Equivocation, Error as GrandpaError, round::State as RoundState, diff --git a/client/finality-grandpa/src/finality_proof.rs b/client/finality-grandpa/src/finality_proof.rs index d52db6c099859..2c85839b5e364 100644 --- a/client/finality-grandpa/src/finality_proof.rs +++ b/client/finality-grandpa/src/finality_proof.rs @@ -34,16 +34,15 @@ //! finality proof (that finalizes some block C that is ancestor of the B and descendant //! of the U) could be returned. -use std::iter; use std::sync::Arc; use log::{trace, warn}; use sp_blockchain::{Backend as BlockchainBackend, Error as ClientError, Result as ClientResult}; use sc_client_api::{ - backend::Backend, CallExecutor, StorageProof, + backend::Backend, StorageProof, light::{FetchChecker, RemoteReadRequest}, + StorageProvider, ProofProvider, }; -use sc_client::Client; use parity_scale_codec::{Encode, Decode}; use finality_grandpa::BlockNumberOps; use sp_runtime::{ @@ -67,12 +66,25 @@ pub trait AuthoritySetForFinalityProver: Send + Sync { fn prove_authorities(&self, block: &BlockId) -> ClientResult; } -/// Client-based implementation of AuthoritySetForFinalityProver. -impl AuthoritySetForFinalityProver for Client +/// Trait that combines `StorageProvider` and `ProofProvider` +pub trait StorageAndProofProvider: StorageProvider + ProofProvider + Send + Sync where - B: Backend + Send + Sync + 'static, - E: CallExecutor + 'static + Clone + Send + Sync, - RA: Send + Sync, + Block: BlockT, + BE: Backend + Send + Sync, +{} + +/// Blanket implementation. +impl StorageAndProofProvider for P + where + Block: BlockT, + BE: Backend + Send + Sync, + P: StorageProvider + ProofProvider + Send + Sync, +{} + +/// Implementation of AuthoritySetForFinalityProver. +impl AuthoritySetForFinalityProver for Arc> + where + BE: Backend + Send + Sync + 'static, { fn authorities(&self, block: &BlockId) -> ClientResult { let storage_key = StorageKey(GRANDPA_AUTHORITIES_KEY.to_vec()); @@ -83,7 +95,7 @@ impl AuthoritySetForFinalityProver for Client) -> ClientResult { - self.read_proof(block, iter::once(GRANDPA_AUTHORITIES_KEY)) + self.read_proof(block, &mut std::iter::once(GRANDPA_AUTHORITIES_KEY)) } } @@ -146,11 +158,13 @@ impl FinalityProofProvider /// /// - backend for accessing blockchain data; /// - authority_provider for calling and proving runtime methods. - pub fn new( + pub fn new

( backend: Arc, - authority_provider: Arc>, - ) -> Self { - FinalityProofProvider { backend, authority_provider } + authority_provider: P, + ) -> Self + where P: AuthoritySetForFinalityProver + 'static, + { + FinalityProofProvider { backend, authority_provider: Arc::new(authority_provider) } } } diff --git a/client/finality-grandpa/src/import.rs b/client/finality-grandpa/src/import.rs index 28a08339dcb36..ea1deccdafbf5 100644 --- a/client/finality-grandpa/src/import.rs +++ b/client/finality-grandpa/src/import.rs @@ -541,8 +541,7 @@ impl GrandpaBlockImport - GrandpaBlockImport +impl GrandpaBlockImport where BE: Backend, Client: crate::ClientForGrandpa, diff --git a/client/finality-grandpa/src/lib.rs b/client/finality-grandpa/src/lib.rs index 38c1070d7702b..afee2bec53576 100644 --- a/client/finality-grandpa/src/lib.rs +++ b/client/finality-grandpa/src/lib.rs @@ -57,11 +57,11 @@ use futures::StreamExt; use log::{debug, info}; use futures::channel::mpsc; use sc_client_api::{ + backend::{AuxStore, Backend}, LockImportRun, BlockchainEvents, CallExecutor, - backend::{AuxStore, Backend}, ExecutionStrategy, Finalizer, TransactionFor, + ExecutionStrategy, Finalizer, TransactionFor, ExecutorProvider, }; use sp_blockchain::{HeaderBackend, Error as ClientError, HeaderMetadata}; -use sc_client::Client; use parity_scale_codec::{Decode, Encode}; use sp_runtime::generic::BlockId; use sp_runtime::traits::{NumberFor, Block as BlockT, DigestFor, Zero}; @@ -96,7 +96,7 @@ mod observer; mod until_imported; mod voting_rule; -pub use finality_proof::FinalityProofProvider; +pub use finality_proof::{FinalityProofProvider, StorageAndProofProvider}; pub use justification::GrandpaJustification; pub use light_import::light_block_import; pub use voting_rule::{ @@ -266,7 +266,7 @@ impl BlockStatus for Arc where pub trait ClientForGrandpa: LockImportRun + Finalizer + AuxStore + HeaderMetadata + HeaderBackend - + BlockchainEvents + ProvideRuntimeApi + + BlockchainEvents + ProvideRuntimeApi + ExecutorProvider + BlockImport, Error = sp_consensus::Error> where BE: Backend, @@ -279,7 +279,7 @@ impl ClientForGrandpa for T Block: BlockT, T: LockImportRun + Finalizer + AuxStore + HeaderMetadata + HeaderBackend - + BlockchainEvents + ProvideRuntimeApi + + BlockchainEvents + ProvideRuntimeApi + ExecutorProvider + BlockImport, Error = sp_consensus::Error>, {} @@ -387,11 +387,8 @@ pub trait GenesisAuthoritySetProvider { fn get(&self) -> Result; } -impl GenesisAuthoritySetProvider for Client - where - B: Backend + Send + Sync + 'static, - E: CallExecutor + Send + Sync, - RA: Send + Sync, +impl GenesisAuthoritySetProvider for Arc> + where E: CallExecutor, { fn get(&self) -> Result { // This implementation uses the Grandpa runtime API instead of reading directly from the diff --git a/client/finality-grandpa/src/light_import.rs b/client/finality-grandpa/src/light_import.rs index 258ea81bd5197..276f5d0f28d7a 100644 --- a/client/finality-grandpa/src/light_import.rs +++ b/client/finality-grandpa/src/light_import.rs @@ -18,7 +18,9 @@ use std::collections::HashMap; use std::sync::Arc; use log::{info, trace, warn}; use parking_lot::RwLock; -use sc_client_api::backend::{AuxStore, Backend, Finalizer, TransactionFor}; +use sc_client_api::{ + backend::{AuxStore, Backend, Finalizer, TransactionFor}, +}; use sp_blockchain::{HeaderBackend, Error as ClientError, well_known_cache_keys}; use parity_scale_codec::{Encode, Decode}; use sp_consensus::{ diff --git a/client/finality-grandpa/src/observer.rs b/client/finality-grandpa/src/observer.rs index 97352b68e3299..921e5a3dd5b14 100644 --- a/client/finality-grandpa/src/observer.rs +++ b/client/finality-grandpa/src/observer.rs @@ -328,7 +328,7 @@ impl Future for ObserverWork where B: BlockT, BE: Backend + Unpin + 'static, - C: crate::ClientForGrandpa+ 'static, + C: crate::ClientForGrandpa + 'static, N: NetworkT, NumberFor: BlockNumberOps, { diff --git a/client/finality-grandpa/src/tests.rs b/client/finality-grandpa/src/tests.rs index aedcb20a59838..0774194d7eb52 100644 --- a/client/finality-grandpa/src/tests.rs +++ b/client/finality-grandpa/src/tests.rs @@ -39,7 +39,7 @@ use sp_consensus::{ use std::{ collections::{HashMap, HashSet}, result, - pin::Pin, task, + pin::Pin, }; use parity_scale_codec::Decode; use sp_runtime::traits::{Block as BlockT, Header as HeaderT, HashFor}; @@ -170,8 +170,7 @@ impl TestNetFactory for GrandpaTestNet { ) -> Option>> { match client { PeersClient::Full(_, ref backend) => { - let authorities_provider = Arc::new(self.test_config.clone()); - Some(Arc::new(FinalityProofProvider::new(backend.clone(), authorities_provider))) + Some(Arc::new(FinalityProofProvider::new(backend.clone(), self.test_config.clone()))) }, PeersClient::Light(_, _) => None, } diff --git a/client/network/src/chain.rs b/client/network/src/chain.rs index b991a0e65208c..3c075ec881ca1 100644 --- a/client/network/src/chain.rs +++ b/client/network/src/chain.rs @@ -18,7 +18,7 @@ use sc_client::Client as SubstrateClient; use sp_blockchain::{Error, Info as BlockchainInfo}; -use sc_client_api::{ChangesProof, StorageProof, CallExecutor}; +use sc_client_api::{ChangesProof, StorageProof, CallExecutor, ProofProvider}; use sp_consensus::{BlockImport, BlockStatus, Error as ConsensusError}; use sp_runtime::traits::{Block as BlockT, Header as HeaderT, NumberFor}; use sp_runtime::generic::{BlockId}; @@ -50,7 +50,11 @@ pub trait Client: Send + Sync { -> Result<(Block::Header, StorageProof), Error>; /// Get storage read execution proof. - fn read_proof(&self, block: &Block::Hash, keys: &[Vec]) -> Result; + fn read_proof( + &self, + block: &Block::Hash, + keys: &mut dyn Iterator, + ) -> Result; /// Get child storage read execution proof. fn read_child_proof( @@ -58,7 +62,7 @@ pub trait Client: Send + Sync { block: &Block::Hash, storage_key: &[u8], child_info: ChildInfo, - keys: &[Vec], + keys: &mut dyn Iterator, ) -> Result; /// Get method execution proof. @@ -125,14 +129,19 @@ impl Client for SubstrateClient where (self as &SubstrateClient).justification(id) } - fn header_proof(&self, block_number: ::Number) - -> Result<(Block::Header, StorageProof), Error> - { - (self as &SubstrateClient).header_proof(&BlockId::Number(block_number)) + fn header_proof( + &self, + block_number: ::Number, + )-> Result<(Block::Header, StorageProof), Error> { + ProofProvider::::header_proof(self, &BlockId::Number(block_number)) } - fn read_proof(&self, block: &Block::Hash, keys: &[Vec]) -> Result { - (self as &SubstrateClient).read_proof(&BlockId::Hash(block.clone()), keys) + fn read_proof( + &self, + block: &Block::Hash, + keys: &mut dyn Iterator, + ) -> Result { + ProofProvider::::read_proof(self, &BlockId::Hash(block.clone()), keys) } fn read_child_proof( @@ -140,10 +149,9 @@ impl Client for SubstrateClient where block: &Block::Hash, storage_key: &[u8], child_info: ChildInfo, - keys: &[Vec], + keys: &mut dyn Iterator, ) -> Result { - (self as &SubstrateClient) - .read_child_proof(&BlockId::Hash(block.clone()), storage_key, child_info, keys) + ProofProvider::::read_child_proof(self, &BlockId::Hash(block.clone()), storage_key, child_info, keys) } fn execution_proof( @@ -152,7 +160,8 @@ impl Client for SubstrateClient where method: &str, data: &[u8], ) -> Result<(Vec, StorageProof), Error> { - (self as &SubstrateClient).execution_proof( + ProofProvider::::execution_proof( + self, &BlockId::Hash(block.clone()), method, data, @@ -168,7 +177,7 @@ impl Client for SubstrateClient where storage_key: Option<&StorageKey>, key: &StorageKey, ) -> Result, Error> { - (self as &SubstrateClient).key_changes_proof(first, last, min, max, storage_key, key) + ProofProvider::::key_changes_proof(self, first, last, min, max, storage_key, key) } fn is_descendent_of(&self, base: &Block::Hash, block: &Block::Hash) -> Result { diff --git a/client/network/src/protocol.rs b/client/network/src/protocol.rs index d344321e68dd0..5d7adfdcc3f52 100644 --- a/client/network/src/protocol.rs +++ b/client/network/src/protocol.rs @@ -1473,7 +1473,10 @@ impl Protocol { trace!(target: "sync", "Remote read request {} from {} ({} at {})", request.id, who, keys_str(), request.block); - let proof = match self.context_data.chain.read_proof(&request.block, &request.keys) { + let proof = match self.context_data.chain.read_proof( + &request.block, + &mut request.keys.iter().map(AsRef::as_ref) + ) { Ok(proof) => proof, Err(error) => { trace!(target: "sync", "Remote read request {} from {} ({} at {}) failed with: {}", @@ -1523,7 +1526,7 @@ impl Protocol { &request.block, &request.storage_key, child_info, - &request.keys, + &mut request.keys.iter().map(AsRef::as_ref), ) { Ok(proof) => proof, Err(error) => { diff --git a/client/network/src/protocol/light_client_handler.rs b/client/network/src/protocol/light_client_handler.rs index b531f3515a6ec..a141e134fca05 100644 --- a/client/network/src/protocol/light_client_handler.rs +++ b/client/network/src/protocol/light_client_handler.rs @@ -467,7 +467,7 @@ where let block = Decode::decode(&mut request.block.as_ref())?; - let proof = match self.chain.read_proof(&block, &request.keys) { + let proof = match self.chain.read_proof(&block, &mut request.keys.iter().map(AsRef::as_ref)) { Ok(proof) => proof, Err(error) => { log::trace!("remote read request from {} ({} at {:?}) failed with: {}", @@ -508,7 +508,12 @@ where let proof = if let Some(info) = ChildInfo::resolve_child_info(request.child_type, &request.child_info[..]) { - match self.chain.read_child_proof(&block, &request.storage_key, info, &request.keys) { + match self.chain.read_child_proof( + &block, + &request.storage_key, + info, + &mut request.keys.iter().map(AsRef::as_ref) + ) { Ok(proof) => proof, Err(error) => { log::trace!("remote read child request from {} ({} {} at {:?}) failed with: {}", diff --git a/client/offchain/src/lib.rs b/client/offchain/src/lib.rs index 7fc9671fcbcd8..27a7f508459ba 100644 --- a/client/offchain/src/lib.rs +++ b/client/offchain/src/lib.rs @@ -169,6 +169,7 @@ mod tests { use substrate_test_runtime_client::runtime::Block; use sc_transaction_pool::{BasicPool, FullChainApi}; use sp_transaction_pool::{TransactionPool, InPoolTransaction}; + use sc_client_api::ExecutorProvider; struct MockNetworkStateInfo(); diff --git a/client/rpc/src/author/mod.rs b/client/rpc/src/author/mod.rs index 06bdcf883c689..80a3a4349ed82 100644 --- a/client/rpc/src/author/mod.rs +++ b/client/rpc/src/author/mod.rs @@ -22,8 +22,7 @@ mod tests; use std::{sync::Arc, convert::TryInto}; use log::warn; -use sc_client::Client; -use sp_blockchain::Error as ClientError; +use sp_blockchain::{Error as ClientError, HeaderBackend}; use rpc::futures::{ Sink, Future, @@ -36,7 +35,7 @@ use jsonrpc_pubsub::{typed::Subscriber, SubscriptionId}; use codec::{Encode, Decode}; use sp_core::{Bytes, traits::BareCryptoStorePtr}; use sp_api::ProvideRuntimeApi; -use sp_runtime::{generic, traits}; +use sp_runtime::generic; use sp_transaction_pool::{ TransactionPool, InPoolTransaction, TransactionStatus, BlockHash, TxHash, TransactionFor, error::IntoPoolError, @@ -48,9 +47,9 @@ pub use sc_rpc_api::author::*; use self::error::{Error, FutureResult, Result}; /// Authoring API -pub struct Author { +pub struct Author { /// Substrate client - client: Arc>, + client: Arc, /// Transactions pool pool: Arc

, /// Subscriptions manager @@ -59,10 +58,10 @@ pub struct Author { keystore: BareCryptoStorePtr, } -impl Author { +impl Author { /// Create new instance of Authoring API. pub fn new( - client: Arc>, + client: Arc, pool: Arc

, subscriptions: Subscriptions, keystore: BareCryptoStorePtr, @@ -76,18 +75,11 @@ impl Author { } } -impl AuthorApi, BlockHash

> - for Author::Block, RA> -where - B: sc_client_api::backend::Backend<

::Block> + Send + Sync + 'static, - E: sc_client::CallExecutor<

::Block> + Send + Sync + 'static, - P: TransactionPool + Sync + Send + 'static, - P::Block: traits::Block, - P::Error: 'static, - RA: Send + Sync + 'static, - Client: ProvideRuntimeApi, - as ProvideRuntimeApi>::Api: - SessionKeys, +impl AuthorApi, BlockHash

> for Author + where + P: TransactionPool + Sync + Send + 'static, + Client: HeaderBackend + ProvideRuntimeApi + Send + Sync + 'static, + Client::Api: SessionKeys, { type Metadata = crate::metadata::Metadata; @@ -105,7 +97,7 @@ where } fn rotate_keys(&self) -> Result { - let best_block_hash = self.client.chain_info().best_hash; + let best_block_hash = self.client.info().best_hash; self.client.runtime_api().generate_session_keys( &generic::BlockId::Hash(best_block_hash), None, @@ -113,7 +105,7 @@ where } fn has_session_keys(&self, session_keys: Bytes) -> Result { - let best_block_hash = self.client.chain_info().best_hash; + let best_block_hash = self.client.info().best_hash; let keys = self.client.runtime_api().decode_session_keys( &generic::BlockId::Hash(best_block_hash), session_keys.to_vec(), @@ -133,7 +125,7 @@ where Ok(xt) => xt, Err(err) => return Box::new(result(Err(err.into()))), }; - let best_block_hash = self.client.chain_info().best_hash; + let best_block_hash = self.client.info().best_hash; Box::new(self.pool .submit_one(&generic::BlockId::hash(best_block_hash), xt) .compat() @@ -176,7 +168,7 @@ where xt: Bytes, ) { let submit = || -> Result<_> { - let best_block_hash = self.client.chain_info().best_hash; + let best_block_hash = self.client.info().best_hash; let dxt = TransactionFor::

::decode(&mut &xt[..]) .map_err(error::Error::from)?; Ok( diff --git a/client/rpc/src/author/tests.rs b/client/rpc/src/author/tests.rs index 41bfc46d388bd..3093cd9d3b759 100644 --- a/client/rpc/src/author/tests.rs +++ b/client/rpc/src/author/tests.rs @@ -25,8 +25,8 @@ use sp_core::{ }; use rpc::futures::Stream as _; use substrate_test_runtime_client::{ - self, AccountKeyring, runtime::{Extrinsic, Transfer, SessionKeys, RuntimeApi, Block}, - DefaultTestClientBuilderExt, TestClientBuilderExt, Backend, Client, Executor, + self, AccountKeyring, runtime::{Extrinsic, Transfer, SessionKeys, Block}, + DefaultTestClientBuilderExt, TestClientBuilderExt, Backend, Client, }; use sc_transaction_pool::{BasicPool, FullChainApi}; use tokio::runtime; @@ -75,7 +75,7 @@ impl Default for TestSetup { } impl TestSetup { - fn author(&self) -> Author { + fn author(&self) -> Author> { Author { client: self.client.clone(), pool: self.pool.clone(), diff --git a/client/rpc/src/chain/chain_full.rs b/client/rpc/src/chain/chain_full.rs index ff732368fe9d2..ea562d47748c5 100644 --- a/client/rpc/src/chain/chain_full.rs +++ b/client/rpc/src/chain/chain_full.rs @@ -20,37 +20,39 @@ use std::sync::Arc; use rpc::futures::future::result; use sc_rpc_api::Subscriptions; -use sc_client_api::{CallExecutor, backend::Backend}; -use sc_client::Client; +use sc_client_api::{BlockchainEvents, BlockBody}; use sp_runtime::{generic::{BlockId, SignedBlock}, traits::{Block as BlockT}}; use super::{ChainBackend, client_err, error::FutureResult}; +use std::marker::PhantomData; +use sp_blockchain::HeaderBackend; /// Blockchain API backend for full nodes. Reads all the data from local database. -pub struct FullChain { +pub struct FullChain { /// Substrate client. - client: Arc>, + client: Arc, /// Current subscriptions. subscriptions: Subscriptions, + /// phantom member to pin the block type + _phantom: PhantomData, } -impl FullChain { +impl FullChain { /// Create new Chain API RPC handler. - pub fn new(client: Arc>, subscriptions: Subscriptions) -> Self { + pub fn new(client: Arc, subscriptions: Subscriptions) -> Self { Self { client, subscriptions, + _phantom: PhantomData, } } } -impl ChainBackend for FullChain where +impl ChainBackend for FullChain where Block: BlockT + 'static, - B: Backend + Send + Sync + 'static, - E: CallExecutor + Send + Sync + 'static, - RA: Send + Sync + 'static, + Client: BlockBody + HeaderBackend + BlockchainEvents + 'static, { - fn client(&self) -> &Arc> { + fn client(&self) -> &Arc { &self.client } @@ -60,7 +62,7 @@ impl ChainBackend for FullChain) -> FutureResult> { Box::new(result(self.client - .header(&BlockId::Hash(self.unwrap_or_best(hash))) + .header(BlockId::Hash(self.unwrap_or_best(hash))) .map_err(client_err) )) } diff --git a/client/rpc/src/chain/chain_light.rs b/client/rpc/src/chain/chain_light.rs index 3e26bd24bb090..b258c8dd3bc25 100644 --- a/client/rpc/src/chain/chain_light.rs +++ b/client/rpc/src/chain/chain_light.rs @@ -22,7 +22,7 @@ use rpc::futures::future::{result, Future, Either}; use sc_rpc_api::Subscriptions; use sc_client::{ - Client, light::{fetcher::{Fetcher, RemoteBodyRequest}, blockchain::RemoteBlockchain}, + light::{fetcher::{Fetcher, RemoteBodyRequest}, blockchain::RemoteBlockchain}, }; use sp_runtime::{ generic::{BlockId, SignedBlock}, @@ -30,12 +30,14 @@ use sp_runtime::{ }; use super::{ChainBackend, client_err, error::FutureResult}; +use sp_blockchain::HeaderBackend; +use sc_client_api::BlockchainEvents; /// Blockchain API backend for light nodes. Reads all the data from local /// database, if available, or fetches it from remote node otherwise. -pub struct LightChain { +pub struct LightChain { /// Substrate client. - client: Arc>, + client: Arc, /// Current subscriptions. subscriptions: Subscriptions, /// Remote blockchain reference @@ -44,10 +46,10 @@ pub struct LightChain { fetcher: Arc, } -impl> LightChain { +impl> LightChain { /// Create new Chain API RPC handler. pub fn new( - client: Arc>, + client: Arc, subscriptions: Subscriptions, remote_blockchain: Arc>, fetcher: Arc, @@ -61,14 +63,12 @@ impl> LightChain } } -impl ChainBackend for LightChain where +impl ChainBackend for LightChain where Block: BlockT + 'static, - B: sc_client_api::backend::Backend + Send + Sync + 'static, - E: sc_client::CallExecutor + Send + Sync + 'static, - RA: Send + Sync + 'static, + Client: BlockchainEvents + HeaderBackend + Send + Sync + 'static, F: Fetcher + Send + Sync + 'static, { - fn client(&self) -> &Arc> { + fn client(&self) -> &Arc { &self.client } diff --git a/client/rpc/src/chain/mod.rs b/client/rpc/src/chain/mod.rs index 5285de670d8ab..e7a927e780627 100644 --- a/client/rpc/src/chain/mod.rs +++ b/client/rpc/src/chain/mod.rs @@ -32,7 +32,7 @@ use rpc::{ use sc_rpc_api::Subscriptions; use sc_client::{ - self, Client, BlockchainEvents, + self, BlockchainEvents, light::{fetcher::Fetcher, blockchain::RemoteBlockchain}, }; use jsonrpc_pubsub::{typed::Subscriber, SubscriptionId}; @@ -45,16 +45,17 @@ use sp_runtime::{ use self::error::{Result, Error, FutureResult}; pub use sc_rpc_api::chain::*; +use sp_blockchain::HeaderBackend; +use sc_client_api::BlockBody; /// Blockchain backend API -trait ChainBackend: Send + Sync + 'static +trait ChainBackend: Send + Sync + 'static where Block: BlockT + 'static, - B: sc_client_api::backend::Backend + Send + Sync + 'static, - E: sc_client::CallExecutor + Send + Sync + 'static, + Client: HeaderBackend + BlockchainEvents + 'static, { /// Get client reference. - fn client(&self) -> &Arc>; + fn client(&self) -> &Arc; /// Get subscriptions reference. fn subscriptions(&self) -> &Subscriptions; @@ -62,7 +63,7 @@ trait ChainBackend: Send + Sync + 'static /// Tries to unwrap passed block hash, or uses best block hash otherwise. fn unwrap_or_best(&self, hash: Option) -> Block::Hash { match hash.into() { - None => self.client().chain_info().best_hash, + None => self.client().info().best_hash, Some(hash) => hash, } } @@ -81,9 +82,9 @@ trait ChainBackend: Send + Sync + 'static number: Option>>, ) -> Result> { Ok(match number { - None => Some(self.client().chain_info().best_hash), + None => Some(self.client().info().best_hash), Some(num_or_hex) => self.client() - .header(&BlockId::number(num_or_hex.to_number()?)) + .header(BlockId::number(num_or_hex.to_number()?)) .map_err(client_err)? .map(|h| h.hash()), }) @@ -91,7 +92,7 @@ trait ChainBackend: Send + Sync + 'static /// Get hash of the last finalized block in the canon chain. fn finalized_head(&self) -> Result { - Ok(self.client().chain_info().finalized_hash) + Ok(self.client().info().finalized_hash) } /// All new head subscription @@ -104,7 +105,7 @@ trait ChainBackend: Send + Sync + 'static self.client(), self.subscriptions(), subscriber, - || self.client().chain_info().best_hash, + || self.client().info().best_hash, || self.client().import_notification_stream() .map(|notification| Ok::<_, ()>(notification.header)) .compat(), @@ -130,7 +131,7 @@ trait ChainBackend: Send + Sync + 'static self.client(), self.subscriptions(), subscriber, - || self.client().chain_info().best_hash, + || self.client().info().best_hash, || self.client().import_notification_stream() .filter(|notification| future::ready(notification.is_new_best)) .map(|notification| Ok::<_, ()>(notification.header)) @@ -157,7 +158,7 @@ trait ChainBackend: Send + Sync + 'static self.client(), self.subscriptions(), subscriber, - || self.client().chain_info().finalized_hash, + || self.client().info().finalized_hash, || self.client().finality_notification_stream() .map(|notification| Ok::<_, ()>(notification.header)) .compat(), @@ -175,15 +176,13 @@ trait ChainBackend: Send + Sync + 'static } /// Create new state API that works on full node. -pub fn new_full( - client: Arc>, +pub fn new_full( + client: Arc, subscriptions: Subscriptions, -) -> Chain +) -> Chain where Block: BlockT + 'static, - B: sc_client_api::backend::Backend + Send + Sync + 'static, - E: sc_client::CallExecutor + Send + Sync + 'static + Clone, - RA: Send + Sync + 'static, + Client: BlockBody + HeaderBackend + BlockchainEvents + 'static, { Chain { backend: Box::new(self::chain_full::FullChain::new(client, subscriptions)), @@ -191,17 +190,15 @@ pub fn new_full( } /// Create new state API that works on light node. -pub fn new_light>( - client: Arc>, +pub fn new_light>( + client: Arc, subscriptions: Subscriptions, remote_blockchain: Arc>, fetcher: Arc, -) -> Chain +) -> Chain where Block: BlockT + 'static, - B: sc_client_api::backend::Backend + Send + Sync + 'static, - E: sc_client::CallExecutor + Send + Sync + 'static + Clone, - RA: Send + Sync + 'static, + Client: BlockBody + HeaderBackend + BlockchainEvents + 'static, F: Send + Sync + 'static, { Chain { @@ -215,15 +212,15 @@ pub fn new_light>( } /// Chain API with subscriptions support. -pub struct Chain { - backend: Box>, +pub struct Chain { + backend: Box>, } -impl ChainApi, Block::Hash, Block::Header, SignedBlock> for Chain where - Block: BlockT + 'static, - B: sc_client_api::backend::Backend + Send + Sync + 'static, - E: sc_client::CallExecutor + Send + Sync + 'static, - RA: Send + Sync + 'static +impl ChainApi, Block::Hash, Block::Header, SignedBlock> for + Chain + where + Block: BlockT + 'static, + Client: HeaderBackend + BlockchainEvents + 'static, { type Metadata = crate::metadata::Metadata; @@ -281,16 +278,15 @@ impl ChainApi, Block::Hash, Block::Header, Sig } /// Subscribe to new headers. -fn subscribe_headers( - client: &Arc>, +fn subscribe_headers( + client: &Arc, subscriptions: &Subscriptions, subscriber: Subscriber, best_block_hash: G, stream: F, ) where Block: BlockT + 'static, - B: sc_client_api::backend::Backend + Send + Sync + 'static, - E: sc_client::CallExecutor + Send + Sync + 'static, + Client: HeaderBackend + 'static, F: FnOnce() -> S, G: FnOnce() -> Block::Hash, ERR: ::std::fmt::Debug, @@ -298,7 +294,7 @@ fn subscribe_headers( { subscriptions.add(subscriber, |sink| { // send current head right at the start. - let header = client.header(&BlockId::Hash(best_block_hash())) + let header = client.header(BlockId::Hash(best_block_hash())) .map_err(client_err) .and_then(|header| { header.ok_or_else(|| "Best header missing.".to_owned().into()) diff --git a/client/rpc/src/state/mod.rs b/client/rpc/src/state/mod.rs index 8f621cc8afc96..82568866ee3ba 100644 --- a/client/rpc/src/state/mod.rs +++ b/client/rpc/src/state/mod.rs @@ -27,26 +27,26 @@ use jsonrpc_pubsub::{typed::Subscriber, SubscriptionId}; use rpc::{Result as RpcResult, futures::{Future, future::result}}; use sc_rpc_api::Subscriptions; -use sc_client::{Client, CallExecutor, light::{blockchain::RemoteBlockchain, fetcher::Fetcher}}; +use sc_client::{light::{blockchain::RemoteBlockchain, fetcher::Fetcher}}; use sp_core::{Bytes, storage::{StorageKey, StorageData, StorageChangeSet}}; use sp_version::RuntimeVersion; use sp_runtime::traits::Block as BlockT; -use sp_api::{Metadata, ProvideRuntimeApi}; +use sp_api::{Metadata, ProvideRuntimeApi, CallApiAt}; use self::error::{Error, FutureResult}; pub use sc_rpc_api::state::*; +use sc_client_api::{ExecutorProvider, StorageProvider, BlockchainEvents, Backend}; +use sp_blockchain::{HeaderMetadata, HeaderBackend}; const STORAGE_KEYS_PAGED_MAX_COUNT: u32 = 1000; /// State backend API. -pub trait StateBackend: Send + Sync + 'static +pub trait StateBackend: Send + Sync + 'static where Block: BlockT + 'static, - B: sc_client_api::backend::Backend + Send + Sync + 'static, - E: sc_client::CallExecutor + Send + Sync + 'static, - RA: Send + Sync + 'static, + Client: Send + Sync + 'static, { /// Call runtime method at given block. fn call( @@ -194,18 +194,18 @@ pub trait StateBackend: Send + Sync + 'static } /// Create new state API that works on full node. -pub fn new_full( - client: Arc>, +pub fn new_full( + client: Arc, subscriptions: Subscriptions, -) -> State +) -> State where Block: BlockT + 'static, - B: sc_client_api::backend::Backend + Send + Sync + 'static, - E: CallExecutor + Send + Sync + 'static + Clone, - RA: Send + Sync + 'static, - Client: ProvideRuntimeApi, - as ProvideRuntimeApi>::Api: - Metadata, + BE: Backend + 'static, + Client: ExecutorProvider + StorageProvider + HeaderBackend + + HeaderMetadata + BlockchainEvents + + CallApiAt + + ProvideRuntimeApi + Send + Sync + 'static, + Client::Api: Metadata, { State { backend: Box::new(self::state_full::FullState::new(client, subscriptions)), @@ -213,17 +213,19 @@ pub fn new_full( } /// Create new state API that works on light node. -pub fn new_light>( - client: Arc>, +pub fn new_light>( + client: Arc, subscriptions: Subscriptions, remote_blockchain: Arc>, fetcher: Arc, -) -> State +) -> State where Block: BlockT + 'static, - B: sc_client_api::backend::Backend + Send + Sync + 'static, - E: CallExecutor + Send + Sync + 'static + Clone, - RA: Send + Sync + 'static, + BE: Backend + 'static, + Client: ExecutorProvider + StorageProvider + + HeaderMetadata + + ProvideRuntimeApi + HeaderBackend + BlockchainEvents + + Send + Sync + 'static, F: Send + Sync + 'static, { State { @@ -237,16 +239,14 @@ pub fn new_light>( } /// State API with subscriptions support. -pub struct State { - backend: Box>, +pub struct State { + backend: Box>, } -impl StateApi for State +impl StateApi for State where Block: BlockT + 'static, - B: sc_client_api::backend::Backend + Send + Sync + 'static, - E: CallExecutor + Send + Sync + 'static + Clone, - RA: Send + Sync + 'static, + Client: Send + Sync + 'static, { type Metadata = crate::metadata::Metadata; diff --git a/client/rpc/src/state/state_full.rs b/client/rpc/src/state/state_full.rs index 3d5613626e044..b7589d2aefeca 100644 --- a/client/rpc/src/state/state_full.rs +++ b/client/rpc/src/state/state_full.rs @@ -26,12 +26,8 @@ use rpc::{Result as RpcResult, futures::{stream, Future, Sink, Stream, future::r use sc_rpc_api::Subscriptions; use sc_client_api::backend::Backend; -use sp_blockchain::{ - Result as ClientResult, Error as ClientError, HeaderMetadata, CachedHeaderMetadata -}; -use sc_client::{ - Client, CallExecutor, BlockchainEvents -}; +use sp_blockchain::{Result as ClientResult, Error as ClientError, HeaderMetadata, CachedHeaderMetadata, HeaderBackend}; +use sc_client::BlockchainEvents; use sp_core::{ Bytes, storage::{well_known_keys, StorageKey, StorageData, StorageChangeSet, ChildInfo}, }; @@ -40,9 +36,11 @@ use sp_runtime::{ generic::BlockId, traits::{Block as BlockT, NumberFor, SaturatedConversion}, }; -use sp_api::{Metadata, ProvideRuntimeApi}; +use sp_api::{Metadata, ProvideRuntimeApi, CallApiAt}; use super::{StateBackend, error::{FutureResult, Error, Result}, client_err, child_resolution_error}; +use std::marker::PhantomData; +use sc_client_api::{CallExecutor, StorageProvider, ExecutorProvider}; /// Ranges to query in state_queryStorage. struct QueryStorageRange { @@ -59,25 +57,27 @@ struct QueryStorageRange { } /// State API backend for full nodes. -pub struct FullState { - client: Arc>, +pub struct FullState { + client: Arc, subscriptions: Subscriptions, + _phantom: PhantomData<(BE, Block)> } -impl FullState +impl FullState where + BE: Backend, + Client: StorageProvider + HeaderBackend + + HeaderMetadata, Block: BlockT + 'static, - B: Backend + Send + Sync + 'static, - E: CallExecutor + Send + Sync + 'static + Clone, { /// Create new state API backend for full nodes. - pub fn new(client: Arc>, subscriptions: Subscriptions) -> Self { - Self { client, subscriptions } + pub fn new(client: Arc, subscriptions: Subscriptions) -> Self { + Self { client, subscriptions, _phantom: PhantomData } } /// Returns given block hash or best block hash if None is passed. fn block_or_best(&self, hash: Option) -> ClientResult { - Ok(hash.unwrap_or_else(|| self.client.chain_info().best_hash)) + Ok(hash.unwrap_or_else(|| self.client.info().best_hash)) } /// Splits the `query_storage` block range into 'filtered' and 'unfiltered' subranges. @@ -212,14 +212,14 @@ impl FullState } } -impl StateBackend for FullState where +impl StateBackend for FullState where Block: BlockT + 'static, - B: Backend + Send + Sync + 'static, - E: CallExecutor + Send + Sync + 'static + Clone, - RA: Send + Sync + 'static, - Client: ProvideRuntimeApi, - as ProvideRuntimeApi>::Api: - Metadata, + BE: Backend + 'static, + Client: ExecutorProvider + StorageProvider + HeaderBackend + + HeaderMetadata + BlockchainEvents + + CallApiAt + ProvideRuntimeApi + + Send + Sync + 'static, + Client::Api: Metadata, { fn call( &self, @@ -424,7 +424,7 @@ impl StateBackend for FullState StateBackend for FullState>; /// State API backend for light nodes. -pub struct LightState, B, E, RA> { - client: Arc>, +pub struct LightState, Client> { + client: Arc, subscriptions: Subscriptions, version_subscriptions: SimpleSubscriptions, storage_subscriptions: Arc>>, @@ -134,16 +133,14 @@ impl SharedRequests for SimpleSubscriptions where } } -impl + 'static, B, E, RA> LightState +impl + 'static, Client> LightState where Block: BlockT, - B: Backend + Send + Sync + 'static, - E: CallExecutor + Send + Sync + 'static + Clone, - RA: Send + Sync + 'static, + Client: HeaderBackend + Send + Sync + 'static, { /// Create new state API backend for light nodes. pub fn new( - client: Arc>, + client: Arc, subscriptions: Subscriptions, remote_blockchain: Arc>, fetcher: Arc, @@ -164,16 +161,14 @@ impl + 'static, B, E, RA> LightState) -> Block::Hash { - hash.unwrap_or_else(|| self.client.chain_info().best_hash) + hash.unwrap_or_else(|| self.client.info().best_hash) } } -impl StateBackend for LightState +impl StateBackend for LightState where Block: BlockT, - B: Backend + Send + Sync + 'static, - E: CallExecutor + Send + Sync + 'static + Clone, - RA: Send + Sync + 'static, + Client: BlockchainEvents + HeaderBackend + Send + Sync + 'static, F: Fetcher + 'static { fn call( diff --git a/client/service/src/builder.rs b/client/service/src/builder.rs index bfb979c19e07c..096f492e6468b 100644 --- a/client/service/src/builder.rs +++ b/client/service/src/builder.rs @@ -23,6 +23,7 @@ use sc_client_api::{ BlockchainEvents, backend::RemoteBackend, light::RemoteBlockchain, execution_extensions::ExtensionsFactory, + ExecutorProvider, CallExecutor }; use sc_client::Client; use sc_chain_spec::{RuntimeGenesis, Extension}; @@ -799,7 +800,9 @@ ServiceBuilder< TBackend::OffchainStorage, TBl >, - >, Error> { + >, Error> + where TExec: CallExecutor, + { let ServiceBuilder { marker: _, mut config, diff --git a/client/service/src/chain_ops.rs b/client/service/src/chain_ops.rs index 03db9232a1051..350aac9175813 100644 --- a/client/service/src/chain_ops.rs +++ b/client/service/src/chain_ops.rs @@ -35,6 +35,7 @@ use sp_consensus::{ use sc_executor::{NativeExecutor, NativeExecutionDispatch}; use std::{io::{Read, Write, Seek}, pin::Pin}; +use sc_client_api::BlockBody; /// Build a chain spec json pub fn build_spec(spec: ChainSpec, raw: bool) -> error::Result where diff --git a/client/src/client.rs b/client/src/client.rs index 89414870391ec..c921d297012cb 100644 --- a/client/src/client.rs +++ b/client/src/client.rs @@ -66,7 +66,8 @@ pub use sc_client_api::{ backend::{ self, BlockImportOperation, PrunableStateChangesTrieStorage, ClientImportOperation, Finalizer, ImportSummary, NewBlockState, - LockImportRun, changes_tries_state_at_block, + changes_tries_state_at_block, StorageProvider, + LockImportRun, }, client::{ ImportNotifications, FinalityNotification, FinalityNotifications, BlockImportNotification, @@ -75,7 +76,7 @@ pub use sc_client_api::{ }, execution_extensions::{ExecutionExtensions, ExecutionStrategies}, notifications::{StorageNotifications, StorageEventStream}, - CallExecutor, + CallExecutor, ExecutorProvider, ProofProvider, }; use sp_blockchain::Error; use prometheus_endpoint::Registry; @@ -85,6 +86,7 @@ use crate::{ light::{call_executor::prove_execution, fetcher::ChangesProof}, in_mem, genesis, cht, block_rules::{BlockRules, LookupResult as BlockLookupResult}, }; +use crate::client::backend::KeyIterator; /// Substrate Client pub struct Client where Block: BlockT { @@ -100,46 +102,6 @@ pub struct Client where Block: BlockT { _phantom: PhantomData, } -/// An `Iterator` that iterates keys in a given block under a prefix. -pub struct KeyIterator<'a, State, Block> { - state: State, - prefix: Option<&'a StorageKey>, - current_key: Vec, - _phantom: PhantomData, -} - -impl <'a, State, Block> KeyIterator<'a, State, Block> { - fn new(state: State, prefix: Option<&'a StorageKey>, current_key: Vec) -> Self { - Self { - state, - prefix, - current_key, - _phantom: PhantomData, - } - } -} - -impl<'a, State, Block> Iterator for KeyIterator<'a, State, Block> where - Block: BlockT, - State: StateBackend>, -{ - type Item = StorageKey; - - fn next(&mut self) -> Option { - let next_key = self.state - .next_storage_key(&self.current_key) - .ok() - .flatten()?; - if let Some(prefix) = self.prefix { - if !next_key.starts_with(&prefix.0[..]) { - return None; - } - } - self.current_key = next_key.clone(); - Some(StorageKey(next_key)) - } -} - // used in importing a block, where additional changes are made after the runtime // executed. enum PrePostHeader { @@ -324,119 +286,14 @@ impl Client where }) } - /// Get a reference to the execution extensions. - pub fn execution_extensions(&self) -> &ExecutionExtensions { - &self.execution_extensions - } - /// Get a reference to the state at a given block. pub fn state_at(&self, block: &BlockId) -> sp_blockchain::Result { self.backend.state_at(*block) } - /// Given a `BlockId` and a key prefix, return the matching storage keys in that block. - pub fn storage_keys(&self, id: &BlockId, key_prefix: &StorageKey) -> sp_blockchain::Result> { - let keys = self.state_at(id)?.keys(&key_prefix.0).into_iter().map(StorageKey).collect(); - 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, - id: &BlockId, - prefix: Option<&'a StorageKey>, - start_key: Option<&StorageKey> - ) -> sp_blockchain::Result> { - let state = self.state_at(id)?; - let start_key = start_key - .or(prefix) - .map(|key| key.0.clone()) - .unwrap_or_else(Vec::new); - Ok(KeyIterator::new(state, prefix, start_key)) - } - - /// 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> - { - Ok(self.state_at(id)? - .storage(&key.0).map_err(|e| sp_blockchain::Error::from_state(Box::new(e)))? - .map(StorageData) - ) - } - - /// 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> - { - Ok(self.state_at(id)? - .storage_hash(&key.0).map_err(|e| sp_blockchain::Error::from_state(Box::new(e)))? - ) - } - - /// Given a `BlockId`, a key prefix, and a child storage key, return the matching child storage keys. - pub fn child_storage_keys( - &self, - id: &BlockId, - child_storage_key: &StorageKey, - child_info: ChildInfo, - key_prefix: &StorageKey - ) -> sp_blockchain::Result> { - let keys = self.state_at(id)? - .child_keys(&child_storage_key.0, child_info, &key_prefix.0) - .into_iter() - .map(StorageKey) - .collect(); - Ok(keys) - } - - /// Given a `BlockId`, a key and a child storage key, return the value under the key in that block. - pub fn child_storage( - &self, - id: &BlockId, - storage_key: &StorageKey, - child_info: ChildInfo, - key: &StorageKey - ) -> sp_blockchain::Result> { - Ok(self.state_at(id)? - .child_storage(&storage_key.0, child_info, &key.0) - .map_err(|e| sp_blockchain::Error::from_state(Box::new(e)))? - .map(StorageData)) - } - - /// Given a `BlockId`, a key and a child storage key, return the hash under the key in that block. - pub fn child_storage_hash( - &self, - id: &BlockId, - storage_key: &StorageKey, - child_info: ChildInfo, - key: &StorageKey - ) -> sp_blockchain::Result> { - Ok(self.state_at(id)? - .child_storage_hash(&storage_key.0, child_info, &key.0) - .map_err(|e| sp_blockchain::Error::from_state(Box::new(e)))? - ) - } - /// Get the code at a given block. pub fn code_at(&self, id: &BlockId) -> sp_blockchain::Result> { - Ok(self.storage(id, &StorageKey(well_known_keys::CODE.to_vec()))? + Ok(StorageProvider::storage(self, id, &StorageKey(well_known_keys::CODE.to_vec()))? .expect("None is returned if there's no value stored for the given key;\ ':code' key is always defined; qed").0) } @@ -446,57 +303,6 @@ impl Client where self.executor.runtime_version(id) } - /// Get call executor reference. - pub fn executor(&self) -> &E { - &self.executor - } - - /// Reads storage value at a given block + key, returning read proof. - pub fn read_proof(&self, id: &BlockId, keys: I) -> sp_blockchain::Result where - I: IntoIterator, - I::Item: AsRef<[u8]>, - { - self.state_at(id) - .and_then(|state| prove_read(state, keys) - .map_err(Into::into)) - } - - /// Reads child storage value at a given block + storage_key + key, returning - /// read proof. - pub fn read_child_proof( - &self, - id: &BlockId, - storage_key: &[u8], - child_info: ChildInfo, - keys: I, - ) -> sp_blockchain::Result where - I: IntoIterator, - I::Item: AsRef<[u8]>, - { - self.state_at(id) - .and_then(|state| prove_child_read(state, storage_key, child_info, keys) - .map_err(Into::into)) - } - - /// Execute a call to a contract on top of state in a block of given hash - /// AND returning execution proof. - /// - /// No changes are made. - pub fn execution_proof(&self, - id: &BlockId, - method: &str, - call_data: &[u8] - ) -> sp_blockchain::Result<(Vec, StorageProof)> { - let state = self.state_at(id)?; - let header = self.prepare_environment_block(id)?; - prove_execution(state, header, &self.executor, method, call_data) - } - - /// Reads given header and generates CHT-based header proof. - pub fn header_proof(&self, id: &BlockId) -> sp_blockchain::Result<(Block::Header, StorageProof)> { - self.header_proof_with_cht_size(id, cht::size()) - } - /// Get block hash by number. pub fn block_hash(&self, block_number: <::Header as HeaderT>::Number @@ -531,112 +337,6 @@ impl Client where Ok((header, proof)) } - /// Get longest range within [first; last] that is possible to use in `key_changes` - /// and `key_changes_proof` calls. - /// Range could be shortened from the beginning if some changes tries have been pruned. - /// Returns Ok(None) if changes tries are not supported. - pub fn max_key_changes_range( - &self, - first: NumberFor, - last: BlockId, - ) -> sp_blockchain::Result, BlockId)>> { - let last_number = self.backend.blockchain().expect_block_number_from_id(&last)?; - let last_hash = self.backend.blockchain().expect_block_hash_from_id(&last)?; - if first > last_number { - return Err(sp_blockchain::Error::ChangesTrieAccessFailed("Invalid changes trie range".into())); - } - - let (storage, configs) = match self.require_changes_trie(first, last_hash, false).ok() { - Some((storage, configs)) => (storage, configs), - None => return Ok(None), - }; - - let first_available_changes_trie = configs.last().map(|config| config.0); - match first_available_changes_trie { - Some(first_available_changes_trie) => { - let oldest_unpruned = storage.oldest_pruned_digest_range_end(); - let first = std::cmp::max(first_available_changes_trie, oldest_unpruned); - Ok(Some((first, last))) - }, - None => Ok(None) - } - } - - /// Get pairs of (block, extrinsic) where key has been changed at given blocks range. - /// Works only for runtimes that are supporting changes tries. - /// - /// Changes are returned in descending order (i.e. last block comes first). - pub fn key_changes( - &self, - first: NumberFor, - last: BlockId, - storage_key: Option<&StorageKey>, - key: &StorageKey - ) -> sp_blockchain::Result, u32)>> { - let last_number = self.backend.blockchain().expect_block_number_from_id(&last)?; - let last_hash = self.backend.blockchain().expect_block_hash_from_id(&last)?; - let (storage, configs) = self.require_changes_trie(first, last_hash, true)?; - - let mut result = Vec::new(); - let best_number = self.backend.blockchain().info().best_number; - for (config_zero, config_end, config) in configs { - let range_first = ::std::cmp::max(first, config_zero + One::one()); - let range_anchor = match config_end { - Some((config_end_number, config_end_hash)) => if last_number > config_end_number { - ChangesTrieAnchorBlockId { hash: config_end_hash, number: config_end_number } - } else { - ChangesTrieAnchorBlockId { hash: convert_hash(&last_hash), number: last_number } - }, - None => ChangesTrieAnchorBlockId { hash: convert_hash(&last_hash), number: last_number }, - }; - - let config_range = ChangesTrieConfigurationRange { - config: &config, - zero: config_zero.clone(), - end: config_end.map(|(config_end_number, _)| config_end_number), - }; - let result_range: Vec<(NumberFor, u32)> = key_changes::, _>( - config_range, - storage.storage(), - range_first, - &range_anchor, - best_number, - storage_key.as_ref().map(|x| &x.0[..]), - &key.0) - .and_then(|r| r.map(|r| r.map(|(block, tx)| (block, tx))).collect::>()) - .map_err(|err| sp_blockchain::Error::ChangesTrieAccessFailed(err))?; - result.extend(result_range); - } - - Ok(result) - } - - /// Get proof for computation of (block, extrinsic) pairs where key has been changed at given blocks range. - /// `min` is the hash of the first block, which changes trie root is known to the requester - when we're using - /// changes tries from ascendants of this block, we should provide proofs for changes tries roots - /// `max` is the hash of the last block known to the requester - we can't use changes tries from descendants - /// of this block. - /// Works only for runtimes that are supporting changes tries. - pub fn key_changes_proof( - &self, - first: Block::Hash, - last: Block::Hash, - min: Block::Hash, - max: Block::Hash, - storage_key: Option<&StorageKey>, - key: &StorageKey, - ) -> sp_blockchain::Result> { - self.key_changes_proof_with_cht_size( - first, - last, - min, - max, - storage_key, - key, - cht::size(), - ) - } - /// Does the same work as `key_changes_proof`, but assumes that CHTs are of passed size. pub fn key_changes_proof_with_cht_size( &self, @@ -1344,17 +1044,6 @@ impl Client where self.backend.blockchain().justification(*id) } - /// Get full block by id. - pub fn block(&self, id: &BlockId) - -> sp_blockchain::Result>> - { - Ok(match (self.header(id)?, self.body(id)?, self.justification(id)?) { - (Some(header), Some(extrinsics), justification) => - Some(SignedBlock { block: Block::new(header, extrinsics), justification }), - _ => None, - }) - } - /// Gets the uncles of the block with `target_hash` going back `max_generation` ancestors. pub fn uncles(&self, target_hash: Block::Hash, max_generation: NumberFor) -> sp_blockchain::Result> { let load_header = |id: Block::Hash| -> sp_blockchain::Result { @@ -1399,6 +1088,70 @@ impl Client where } } +impl ProofProvider for Client where + B: backend::Backend, + E: CallExecutor, + Block: BlockT, +{ + fn read_proof( + &self, + id: &BlockId, + keys: &mut dyn Iterator, + ) -> sp_blockchain::Result { + self.state_at(id) + .and_then(|state| prove_read(state, keys) + .map_err(Into::into)) + } + + fn read_child_proof( + &self, + id: &BlockId, + storage_key: &[u8], + child_info: ChildInfo, + keys: &mut dyn Iterator, + ) -> sp_blockchain::Result { + self.state_at(id) + .and_then(|state| prove_child_read(state, storage_key, child_info, keys) + .map_err(Into::into)) + } + + fn execution_proof( + &self, + id: &BlockId, + method: &str, + call_data: &[u8] + ) -> sp_blockchain::Result<(Vec, StorageProof)> { + let state = self.state_at(id)?; + let header = self.prepare_environment_block(id)?; + prove_execution(state, header, &self.executor, method, call_data) + } + + fn header_proof(&self, id: &BlockId) -> sp_blockchain::Result<(Block::Header, StorageProof)> { + self.header_proof_with_cht_size(id, cht::size()) + } + + fn key_changes_proof( + &self, + first: Block::Hash, + last: Block::Hash, + min: Block::Hash, + max: Block::Hash, + storage_key: Option<&StorageKey>, + key: &StorageKey, + ) -> sp_blockchain::Result> { + self.key_changes_proof_with_cht_size( + first, + last, + min, + max, + storage_key, + key, + cht::size(), + ) + } +} + + impl BlockBuilderProvider for Client where B: backend::Backend + Send + Sync + 'static, @@ -1425,6 +1178,196 @@ impl BlockBuilderProvider for Client ExecutorProvider for Client where + B: backend::Backend, + E: CallExecutor, + Block: BlockT, +{ + type Executor = E; + + fn executor(&self) -> &Self::Executor { + &self.executor + } + + fn execution_extensions(&self) -> &ExecutionExtensions { + &self.execution_extensions + } +} + +impl StorageProvider for Client where + B: backend::Backend, + E: CallExecutor, + Block: BlockT, +{ + fn storage_keys(&self, id: &BlockId, key_prefix: &StorageKey) -> sp_blockchain::Result> { + let keys = self.state_at(id)?.keys(&key_prefix.0).into_iter().map(StorageKey).collect(); + Ok(keys) + } + + 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) + } + + + fn storage_keys_iter<'a>( + &self, + id: &BlockId, + prefix: Option<&'a StorageKey>, + start_key: Option<&StorageKey> + ) -> sp_blockchain::Result> { + let state = self.state_at(id)?; + let start_key = start_key + .or(prefix) + .map(|key| key.0.clone()) + .unwrap_or_else(Vec::new); + Ok(KeyIterator::new(state, prefix, start_key)) + } + + + 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) + ) + } + + + fn storage_hash(&self, id: &BlockId, key: &StorageKey) -> sp_blockchain::Result> + { + Ok(self.state_at(id)? + .storage_hash(&key.0).map_err(|e| sp_blockchain::Error::from_state(Box::new(e)))? + ) + } + + + fn child_storage_keys( + &self, + id: &BlockId, + child_storage_key: &StorageKey, + child_info: ChildInfo, + key_prefix: &StorageKey + ) -> sp_blockchain::Result> { + let keys = self.state_at(id)? + .child_keys(&child_storage_key.0, child_info, &key_prefix.0) + .into_iter() + .map(StorageKey) + .collect(); + Ok(keys) + } + + + fn child_storage( + &self, + id: &BlockId, + storage_key: &StorageKey, + child_info: ChildInfo, + key: &StorageKey + ) -> sp_blockchain::Result> { + Ok(self.state_at(id)? + .child_storage(&storage_key.0, child_info, &key.0) + .map_err(|e| sp_blockchain::Error::from_state(Box::new(e)))? + .map(StorageData)) + } + + + fn child_storage_hash( + &self, + id: &BlockId, + storage_key: &StorageKey, + child_info: ChildInfo, + key: &StorageKey + ) -> sp_blockchain::Result> { + Ok(self.state_at(id)? + .child_storage_hash(&storage_key.0, child_info, &key.0) + .map_err(|e| sp_blockchain::Error::from_state(Box::new(e)))? + ) + } + + fn max_key_changes_range( + &self, + first: NumberFor, + last: BlockId, + ) -> sp_blockchain::Result, BlockId)>> { + let last_number = self.backend.blockchain().expect_block_number_from_id(&last)?; + let last_hash = self.backend.blockchain().expect_block_hash_from_id(&last)?; + if first > last_number { + return Err(sp_blockchain::Error::ChangesTrieAccessFailed("Invalid changes trie range".into())); + } + + let (storage, configs) = match self.require_changes_trie(first, last_hash, false).ok() { + Some((storage, configs)) => (storage, configs), + None => return Ok(None), + }; + + let first_available_changes_trie = configs.last().map(|config| config.0); + match first_available_changes_trie { + Some(first_available_changes_trie) => { + let oldest_unpruned = storage.oldest_pruned_digest_range_end(); + let first = std::cmp::max(first_available_changes_trie, oldest_unpruned); + Ok(Some((first, last))) + }, + None => Ok(None) + } + } + + fn key_changes( + &self, + first: NumberFor, + last: BlockId, + storage_key: Option<&StorageKey>, + key: &StorageKey + ) -> sp_blockchain::Result, u32)>> { + let last_number = self.backend.blockchain().expect_block_number_from_id(&last)?; + let last_hash = self.backend.blockchain().expect_block_hash_from_id(&last)?; + let (storage, configs) = self.require_changes_trie(first, last_hash, true)?; + + let mut result = Vec::new(); + let best_number = self.backend.blockchain().info().best_number; + for (config_zero, config_end, config) in configs { + let range_first = ::std::cmp::max(first, config_zero + One::one()); + let range_anchor = match config_end { + Some((config_end_number, config_end_hash)) => if last_number > config_end_number { + ChangesTrieAnchorBlockId { hash: config_end_hash, number: config_end_number } + } else { + ChangesTrieAnchorBlockId { hash: convert_hash(&last_hash), number: last_number } + }, + None => ChangesTrieAnchorBlockId { hash: convert_hash(&last_hash), number: last_number }, + }; + + let config_range = ChangesTrieConfigurationRange { + config: &config, + zero: config_zero.clone(), + end: config_end.map(|(config_end_number, _)| config_end_number), + }; + let result_range: Vec<(NumberFor, u32)> = key_changes::, _>( + config_range, + storage.storage(), + range_first, + &range_anchor, + best_number, + storage_key.as_ref().map(|x| &x.0[..]), + &key.0) + .and_then(|r| r.map(|r| r.map(|(block, tx)| (block, tx))).collect::>()) + .map_err(|err| sp_blockchain::Error::ChangesTrieAccessFailed(err))?; + result.extend(result_range); + } + + Ok(result) + } +} + impl HeaderMetadata for Client where B: backend::Backend, E: CallExecutor, @@ -1902,6 +1845,15 @@ impl BlockBody for Client ) -> sp_blockchain::Result::Extrinsic>>> { self.body(id) } + + fn block(&self, id: &BlockId) -> sp_blockchain::Result>> + { + Ok(match (self.header(id)?, self.body(id)?, self.justification(id)?) { + (Some(header), Some(extrinsics), justification) => + Some(SignedBlock { block: Block::new(header, extrinsics), justification }), + _ => None, + }) + } } impl backend::AuxStore for Client diff --git a/client/src/light/call_executor.rs b/client/src/light/call_executor.rs index f8db30194b5e6..cae5d5a0aa8e2 100644 --- a/client/src/light/call_executor.rs +++ b/client/src/light/call_executor.rs @@ -40,7 +40,7 @@ use sp_blockchain::{Error as ClientError, Result as ClientResult}; use sc_client_api::{ backend::RemoteBackend, light::RemoteCallRequest, - call_executor::CallExecutor + call_executor::CallExecutor, }; use sc_executor::{RuntimeVersion, NativeVersion}; @@ -288,6 +288,7 @@ mod tests { use sp_core::H256; use sc_client_api::backend::{Backend, NewBlockState}; use crate::in_mem::Backend as InMemBackend; + use sc_client_api::ProofProvider; use sp_runtime::traits::BlakeTwo256; struct DummyCallExecutor; diff --git a/client/src/light/fetcher.rs b/client/src/light/fetcher.rs index c4989e90b5b05..87e21e3c0e10e 100644 --- a/client/src/light/fetcher.rs +++ b/client/src/light/fetcher.rs @@ -349,6 +349,7 @@ pub mod tests { use sp_runtime::{generic::BlockId, traits::BlakeTwo256}; use sp_state_machine::Backend; use super::*; + use sc_client_api::{StorageProvider, ProofProvider}; const CHILD_INFO_1: ChildInfo<'static> = ChildInfo::new_default(b"unique_id_1"); @@ -378,7 +379,7 @@ pub mod tests { .and_then(|v| Decode::decode(&mut &v.0[..]).ok()).unwrap(); let remote_read_proof = remote_client.read_proof( &remote_block_id, - &[well_known_keys::HEAP_PAGES], + &mut std::iter::once(well_known_keys::HEAP_PAGES), ).unwrap(); // check remote read proof locally @@ -426,7 +427,7 @@ pub mod tests { &remote_block_id, b":child_storage:default:child1", CHILD_INFO_1, - &[b"key1"], + &mut std::iter::once("key1".as_bytes()), ).unwrap(); // check locally