diff --git a/core/client/src/light/backend.rs b/core/client/src/light/backend.rs index 6b2f2f5c0af4c83c35e805721c225f1188031137..336e4cba705714d1e29e6560fec0d09733736972 100644 --- a/core/client/src/light/backend.rs +++ b/core/client/src/light/backend.rs @@ -18,7 +18,7 @@ //! Everything else is requested from full nodes on demand. use std::collections::HashMap; -use std::sync::{Arc, Weak}; +use std::sync::Arc; use parking_lot::{RwLock, Mutex}; use sr_primitives::{generic::BlockId, Justification, StorageOverlay, ChildrenStorageOverlay}; @@ -32,7 +32,6 @@ use crate::backend::{ use crate::blockchain::HeaderBackend as BlockchainHeaderBackend; use crate::error::{Error as ClientError, Result as ClientResult}; use crate::light::blockchain::{Blockchain, Storage as BlockchainStorage}; -use crate::light::fetcher::{Fetcher, RemoteReadRequest}; use hash_db::Hasher; use trie::MemoryDB; use consensus::well_known_cache_keys; @@ -40,14 +39,14 @@ use consensus::well_known_cache_keys; const IN_MEMORY_EXPECT_PROOF: &str = "InMemory state backend has Void error type and always succeeds; qed"; /// Light client backend. -pub struct Backend<S, F, H: Hasher> { - blockchain: Arc<Blockchain<S, F>>, +pub struct Backend<S, H: Hasher> { + blockchain: Arc<Blockchain<S>>, genesis_state: RwLock<Option<InMemoryState<H>>>, import_lock: Mutex<()>, } /// Light block (header and justification) import operation. -pub struct ImportOperation<Block: BlockT, S, F, H: Hasher> { +pub struct ImportOperation<Block: BlockT, S, H: Hasher> { header: Option<Block::Header>, cache: HashMap<well_known_cache_keys::Id, Vec<u8>>, leaf_state: NewBlockState, @@ -55,28 +54,21 @@ pub struct ImportOperation<Block: BlockT, S, F, H: Hasher> { finalized_blocks: Vec<BlockId<Block>>, set_head: Option<BlockId<Block>>, storage_update: Option<InMemoryState<H>>, - _phantom: ::std::marker::PhantomData<(S, F)>, + _phantom: ::std::marker::PhantomData<(S)>, } -/// On-demand state. -pub struct OnDemandState<Block: BlockT, S, F> { - fetcher: Weak<F>, - blockchain: Weak<Blockchain<S, F>>, - block: Block::Hash, - cached_header: RwLock<Option<Block::Header>>, -} - -/// On-demand or in-memory genesis state. -pub enum OnDemandOrGenesisState<Block: BlockT, S, F, H: Hasher> { - /// On-demand state - storage values are fetched from remote nodes. - OnDemand(OnDemandState<Block, S, F>), +/// Either in-memory genesis state, or locally-unavailable state. +pub enum GenesisOrUnavailableState<H: Hasher> { /// Genesis state - storage values are stored in-memory. Genesis(InMemoryState<H>), + /// We know that state exists, but all calls will fail with error, because it + /// isn't locally available. + Unavailable, } -impl<S, F, H: Hasher> Backend<S, F, H> { +impl<S, H: Hasher> Backend<S, H> { /// Create new light backend. - pub fn new(blockchain: Arc<Blockchain<S, F>>) -> Self { + pub fn new(blockchain: Arc<Blockchain<S>>) -> Self { Self { blockchain, genesis_state: RwLock::new(None), @@ -85,12 +77,12 @@ impl<S, F, H: Hasher> Backend<S, F, H> { } /// Get shared blockchain reference. - pub fn blockchain(&self) -> &Arc<Blockchain<S, F>> { + pub fn blockchain(&self) -> &Arc<Blockchain<S>> { &self.blockchain } } -impl<S: AuxStore, F, H: Hasher> AuxStore for Backend<S, F, H> { +impl<S: AuxStore, H: Hasher> AuxStore for Backend<S, H> { fn insert_aux< 'a, 'b: 'a, @@ -106,16 +98,15 @@ impl<S: AuxStore, F, H: Hasher> AuxStore for Backend<S, F, H> { } } -impl<S, F, Block, H> ClientBackend<Block, H> for Backend<S, F, H> where +impl<S, Block, H> ClientBackend<Block, H> for Backend<S, H> where Block: BlockT, S: BlockchainStorage<Block>, - F: Fetcher<Block>, H: Hasher<Out=Block::Hash>, H::Out: Ord, { - type BlockImportOperation = ImportOperation<Block, S, F, H>; - type Blockchain = Blockchain<S, F>; - type State = OnDemandOrGenesisState<Block, S, F, H>; + type BlockImportOperation = ImportOperation<Block, S, H>; + type Blockchain = Blockchain<S>; + type State = GenesisOrUnavailableState<H>; type ChangesTrieStorage = in_mem::ChangesTrieStorage<Block, H>; type OffchainStorage = in_mem::OffchainStorage; @@ -183,7 +174,7 @@ impl<S, F, Block, H> ClientBackend<Block, H> for Backend<S, F, H> where self.blockchain.storage().finalize_header(block) } - fn blockchain(&self) -> &Blockchain<S, F> { + fn blockchain(&self) -> &Blockchain<S> { &self.blockchain } @@ -205,22 +196,17 @@ impl<S, F, Block, H> ClientBackend<Block, H> for Backend<S, F, H> where // special case for genesis block if block_number.is_zero() { if let Some(genesis_state) = self.genesis_state.read().clone() { - return Ok(OnDemandOrGenesisState::Genesis(genesis_state)); + return Ok(GenesisOrUnavailableState::Genesis(genesis_state)); } } - // else create on-demand state - let block_hash = self.blockchain.expect_block_hash_from_id(&block)?; - Ok(OnDemandOrGenesisState::OnDemand(OnDemandState { - fetcher: self.blockchain.fetcher(), - blockchain: Arc::downgrade(&self.blockchain), - block: block_hash, - cached_header: RwLock::new(None), - })) + // else return unavailable state. We do not return error here, because error + // would mean that we do not know this state at all. But we know that it exists + Ok(GenesisOrUnavailableState::Unavailable) } fn revert(&self, _n: NumberFor<Block>) -> ClientResult<NumberFor<Block>> { - Err(ClientError::NotAvailableOnLightClient.into()) + Err(ClientError::NotAvailableOnLightClient) } fn get_import_lock(&self) -> &Mutex<()> { @@ -228,11 +214,10 @@ impl<S, F, Block, H> ClientBackend<Block, H> for Backend<S, F, H> where } } -impl<S, F, Block, H> RemoteBackend<Block, H> for Backend<S, F, H> +impl<S, Block, H> RemoteBackend<Block, H> for Backend<S, H> where Block: BlockT, S: BlockchainStorage<Block> + 'static, - F: Fetcher<Block> + 'static, H: Hasher<Out=Block::Hash>, H::Out: Ord, { @@ -248,15 +233,14 @@ where } } -impl<S, F, Block, H> BlockImportOperation<Block, H> for ImportOperation<Block, S, F, H> +impl<S, Block, H> BlockImportOperation<Block, H> for ImportOperation<Block, S, H> where Block: BlockT, - F: Fetcher<Block>, S: BlockchainStorage<Block>, H: Hasher<Out=Block::Hash>, H::Out: Ord, { - type State = OnDemandOrGenesisState<Block, S, F, H>; + type State = GenesisOrUnavailableState<H>; fn state(&self) -> ClientResult<Option<&Self::State>> { // None means 'locally-stateless' backend @@ -341,99 +325,9 @@ where } } -impl<Block, S, F, H> StateBackend<H> for OnDemandState<Block, S, F> -where - Block: BlockT, - S: BlockchainStorage<Block>, - F: Fetcher<Block>, - H: Hasher<Out=Block::Hash>, -{ - type Error = ClientError; - type Transaction = (); - type TrieBackendStorage = MemoryDB<H>; - - fn storage(&self, key: &[u8]) -> ClientResult<Option<Vec<u8>>> { - let mut header = self.cached_header.read().clone(); - if header.is_none() { - let cached_header = self.blockchain.upgrade() - .ok_or_else(|| ClientError::UnknownBlock(format!("{}", self.block))) - .and_then(|blockchain| blockchain.expect_header(BlockId::Hash(self.block)))?; - header = Some(cached_header.clone()); - *self.cached_header.write() = Some(cached_header); - } - - futures03::executor::block_on( - self.fetcher.upgrade().ok_or(ClientError::NotAvailableOnLightClient)? - .remote_read(RemoteReadRequest { - block: self.block, - header: header.expect("if block above guarantees that header is_some(); qed"), - key: key.to_vec(), - retry_count: None, - }) - ) - } - - fn child_storage(&self, _storage_key: &[u8], _key: &[u8]) -> ClientResult<Option<Vec<u8>>> { - Err(ClientError::NotAvailableOnLightClient.into()) - } - - fn for_keys_with_prefix<A: FnMut(&[u8])>(&self, _prefix: &[u8], _action: A) { - // whole state is not available on light node - } - - fn for_key_values_with_prefix<A: FnMut(&[u8], &[u8])>(&self, _prefix: &[u8], _action: A) { - // whole state is not available on light node - } - - fn for_keys_in_child_storage<A: FnMut(&[u8])>(&self, _storage_key: &[u8], _action: A) { - // whole state is not available on light node - } - - fn for_child_keys_with_prefix<A: FnMut(&[u8])>( - &self, - _storage_key: &[u8], - _prefix: &[u8], - _action: A, - ) { - // whole state is not available on light node - } - - fn storage_root<I>(&self, _delta: I) -> (H::Out, Self::Transaction) - where - I: IntoIterator<Item=(Vec<u8>, Option<Vec<u8>>)> - { - (H::Out::default(), ()) - } - - fn child_storage_root<I>(&self, _key: &[u8], _delta: I) -> (Vec<u8>, bool, Self::Transaction) +impl<H: Hasher> StateBackend<H> for GenesisOrUnavailableState<H> where - I: IntoIterator<Item=(Vec<u8>, Option<Vec<u8>>)> - { - (H::Out::default().as_ref().to_vec(), true, ()) - } - - fn pairs(&self) -> Vec<(Vec<u8>, Vec<u8>)> { - // whole state is not available on light node - Vec::new() - } - - fn keys(&self, _prefix: &[u8]) -> Vec<Vec<u8>> { - // whole state is not available on light node - Vec::new() - } - - fn as_trie_backend(&mut self) -> Option<&TrieBackend<Self::TrieBackendStorage, H>> { - None - } -} - -impl<Block, S, F, H> StateBackend<H> for OnDemandOrGenesisState<Block, S, F, H> -where - Block: BlockT, - F: Fetcher<Block>, - S: BlockchainStorage<Block>, - H: Hasher<Out=Block::Hash>, - H::Out: Ord, + H::Out: Ord, { type Error = ClientError; type Transaction = (); @@ -441,44 +335,39 @@ where fn storage(&self, key: &[u8]) -> ClientResult<Option<Vec<u8>>> { match *self { - OnDemandOrGenesisState::OnDemand(ref state) => - StateBackend::<H>::storage(state, key), - OnDemandOrGenesisState::Genesis(ref state) => + GenesisOrUnavailableState::Genesis(ref state) => Ok(state.storage(key).expect(IN_MEMORY_EXPECT_PROOF)), + GenesisOrUnavailableState::Unavailable => Err(ClientError::NotAvailableOnLightClient), } } fn child_storage(&self, storage_key: &[u8], key: &[u8]) -> ClientResult<Option<Vec<u8>>> { match *self { - OnDemandOrGenesisState::OnDemand(ref state) => - StateBackend::<H>::child_storage(state, storage_key, key), - OnDemandOrGenesisState::Genesis(ref state) => + GenesisOrUnavailableState::Genesis(ref state) => Ok(state.child_storage(storage_key, key).expect(IN_MEMORY_EXPECT_PROOF)), + GenesisOrUnavailableState::Unavailable => Err(ClientError::NotAvailableOnLightClient), } } fn for_keys_with_prefix<A: FnMut(&[u8])>(&self, prefix: &[u8], action: A) { match *self { - OnDemandOrGenesisState::OnDemand(ref state) => - StateBackend::<H>::for_keys_with_prefix(state, prefix, action), - OnDemandOrGenesisState::Genesis(ref state) => state.for_keys_with_prefix(prefix, action), + GenesisOrUnavailableState::Genesis(ref state) => state.for_keys_with_prefix(prefix, action), + GenesisOrUnavailableState::Unavailable => (), } } fn for_key_values_with_prefix<A: FnMut(&[u8], &[u8])>(&self, prefix: &[u8], action: A) { match *self { - OnDemandOrGenesisState::OnDemand(ref state) => - StateBackend::<H>::for_key_values_with_prefix(state, prefix, action), - OnDemandOrGenesisState::Genesis(ref state) => state.for_key_values_with_prefix(prefix, action), + GenesisOrUnavailableState::Genesis(ref state) => state.for_key_values_with_prefix(prefix, action), + GenesisOrUnavailableState::Unavailable => (), } } fn for_keys_in_child_storage<A: FnMut(&[u8])>(&self, storage_key: &[u8], action: A) { match *self { - OnDemandOrGenesisState::OnDemand(ref state) => - StateBackend::<H>::for_keys_in_child_storage(state, storage_key, action), - OnDemandOrGenesisState::Genesis(ref state) => state.for_keys_in_child_storage(storage_key, action), + GenesisOrUnavailableState::Genesis(ref state) => state.for_keys_in_child_storage(storage_key, action), + GenesisOrUnavailableState::Unavailable => (), } } @@ -489,10 +378,9 @@ where action: A, ) { match *self { - OnDemandOrGenesisState::OnDemand(ref state) => - StateBackend::<H>::for_child_keys_with_prefix(state, storage_key, prefix, action), - OnDemandOrGenesisState::Genesis(ref state) => + GenesisOrUnavailableState::Genesis(ref state) => state.for_child_keys_with_prefix(storage_key, prefix, action), + GenesisOrUnavailableState::Unavailable => (), } } @@ -501,12 +389,9 @@ where I: IntoIterator<Item=(Vec<u8>, Option<Vec<u8>>)> { match *self { - OnDemandOrGenesisState::OnDemand(ref state) => - StateBackend::<H>::storage_root(state, delta), - OnDemandOrGenesisState::Genesis(ref state) => { - let (root, _) = state.storage_root(delta); - (root, ()) - }, + GenesisOrUnavailableState::Genesis(ref state) => + (state.storage_root(delta).0, ()), + GenesisOrUnavailableState::Unavailable => (H::Out::default(), ()), } } @@ -515,35 +400,32 @@ where I: IntoIterator<Item=(Vec<u8>, Option<Vec<u8>>)> { match *self { - OnDemandOrGenesisState::OnDemand(ref state) => - StateBackend::<H>::child_storage_root(state, key, delta), - OnDemandOrGenesisState::Genesis(ref state) => { + GenesisOrUnavailableState::Genesis(ref state) => { let (root, is_equal, _) = state.child_storage_root(key, delta); (root, is_equal, ()) }, + GenesisOrUnavailableState::Unavailable => (H::Out::default().as_ref().to_vec(), true, ()), } } fn pairs(&self) -> Vec<(Vec<u8>, Vec<u8>)> { match *self { - OnDemandOrGenesisState::OnDemand(ref state) => - StateBackend::<H>::pairs(state), - OnDemandOrGenesisState::Genesis(ref state) => state.pairs(), + GenesisOrUnavailableState::Genesis(ref state) => state.pairs(), + GenesisOrUnavailableState::Unavailable => Vec::new(), } } fn keys(&self, prefix: &[u8]) -> Vec<Vec<u8>> { match *self { - OnDemandOrGenesisState::OnDemand(ref state) => - StateBackend::<H>::keys(state, prefix), - OnDemandOrGenesisState::Genesis(ref state) => state.keys(prefix), + GenesisOrUnavailableState::Genesis(ref state) => state.keys(prefix), + GenesisOrUnavailableState::Unavailable => Vec::new(), } } fn as_trie_backend(&mut self) -> Option<&TrieBackend<Self::TrieBackendStorage, H>> { match self { - OnDemandOrGenesisState::OnDemand(ref mut state) => state.as_trie_backend(), - OnDemandOrGenesisState::Genesis(ref mut state) => state.as_trie_backend(), + GenesisOrUnavailableState::Genesis(ref mut state) => state.as_trie_backend(), + GenesisOrUnavailableState::Unavailable => None, } } } @@ -561,24 +443,24 @@ mod tests { let def = Default::default(); let header0 = test_client::runtime::Header::new(0, def, def, def, Default::default()); - let backend: Backend<_, _, Blake2Hasher> = Backend::new(Arc::new(DummyBlockchain::new(DummyStorage::new()))); + let backend: Backend<_, Blake2Hasher> = Backend::new(Arc::new(DummyBlockchain::new(DummyStorage::new()))); let mut op = backend.begin_operation().unwrap(); op.set_block_data(header0, None, None, NewBlockState::Final).unwrap(); op.reset_storage(Default::default(), Default::default()).unwrap(); backend.commit_operation(op).unwrap(); match backend.state_at(BlockId::Number(0)).unwrap() { - OnDemandOrGenesisState::Genesis(_) => (), + GenesisOrUnavailableState::Genesis(_) => (), _ => panic!("unexpected state"), } } #[test] - fn remote_state_is_created_when_genesis_state_is_inavailable() { - let backend: Backend<_, _, Blake2Hasher> = Backend::new(Arc::new(DummyBlockchain::new(DummyStorage::new()))); + fn unavailable_state_is_created_when_genesis_state_is_unavailable() { + let backend: Backend<_, Blake2Hasher> = Backend::new(Arc::new(DummyBlockchain::new(DummyStorage::new()))); match backend.state_at(BlockId::Number(0)).unwrap() { - OnDemandOrGenesisState::OnDemand(_) => (), + GenesisOrUnavailableState::Unavailable => (), _ => panic!("unexpected state"), } } diff --git a/core/client/src/light/blockchain.rs b/core/client/src/light/blockchain.rs index 726d2abdc6f2f7adbf8beee5a211927d32cca791..1e1a7669a02c8c50b071f1ae7e0003b03ecf5a32 100644 --- a/core/client/src/light/blockchain.rs +++ b/core/client/src/light/blockchain.rs @@ -18,8 +18,7 @@ //! blocks. CHT roots are stored for headers of ancient blocks. use std::future::Future; -use std::{sync::{Weak, Arc}, collections::HashMap}; -use parking_lot::Mutex; +use std::{sync::Arc, collections::HashMap}; use sr_primitives::{Justification, generic::BlockId}; use sr_primitives::traits::{Block as BlockT, Header as HeaderT, NumberFor, Zero}; @@ -30,7 +29,7 @@ use crate::blockchain::{Backend as BlockchainBackend, BlockStatus, Cache as Bloc HeaderBackend as BlockchainHeaderBackend, Info as BlockchainInfo, ProvideCache}; use crate::cht; use crate::error::{Error as ClientError, Result as ClientResult}; -use crate::light::fetcher::{Fetcher, RemoteBodyRequest, RemoteHeaderRequest}; +use crate::light::fetcher::{Fetcher, RemoteHeaderRequest}; /// Light client blockchain storage. pub trait Storage<Block: BlockT>: AuxStore + BlockchainHeaderBackend<Block> { @@ -95,37 +94,25 @@ pub trait RemoteBlockchain<Block: BlockT>: Send + Sync { } /// Light client blockchain. -pub struct Blockchain<S, F> { - fetcher: Mutex<Weak<F>>, +pub struct Blockchain<S> { storage: S, } -impl<S, F> Blockchain<S, F> { +impl<S> Blockchain<S> { /// Create new light blockchain backed with given storage. pub fn new(storage: S) -> Self { Self { - fetcher: Mutex::new(Default::default()), storage, } } - /// Sets fetcher reference. - pub fn set_fetcher(&self, fetcher: Weak<F>) { - *self.fetcher.lock() = fetcher; - } - - /// Get fetcher weak reference. - pub fn fetcher(&self) -> Weak<F> { - self.fetcher.lock().clone() - } - /// Get storage reference. pub fn storage(&self) -> &S { &self.storage } } -impl<S, F, Block> BlockchainHeaderBackend<Block> for Blockchain<S, F> where Block: BlockT, S: Storage<Block>, F: Fetcher<Block> { +impl<S, Block> BlockchainHeaderBackend<Block> for Blockchain<S> where Block: BlockT, S: Storage<Block> { fn header(&self, id: BlockId<Block>) -> ClientResult<Option<Block::Header>> { match RemoteBlockchain::header(self, id)? { LocalOrRemote::Local(header) => Ok(Some(header)), @@ -151,24 +138,13 @@ impl<S, F, Block> BlockchainHeaderBackend<Block> for Blockchain<S, F> where Bloc } } -impl<S, F, Block> BlockchainBackend<Block> for Blockchain<S, F> where Block: BlockT, S: Storage<Block>, F: Fetcher<Block> { - fn body(&self, id: BlockId<Block>) -> ClientResult<Option<Vec<Block::Extrinsic>>> { - let header = match BlockchainHeaderBackend::header(self, id)? { - Some(header) => header, - None => return Ok(None), - }; - - futures03::executor::block_on( - self.fetcher().upgrade().ok_or(ClientError::NotAvailableOnLightClient)? - .remote_body(RemoteBodyRequest { - header, - retry_count: None, - }) - ).map(Some) +impl<S, Block> BlockchainBackend<Block> for Blockchain<S> where Block: BlockT, S: Storage<Block> { + fn body(&self, _id: BlockId<Block>) -> ClientResult<Option<Vec<Block::Extrinsic>>> { + Err(ClientError::NotAvailableOnLightClient) } fn justification(&self, _id: BlockId<Block>) -> ClientResult<Option<Justification>> { - Ok(None) + Err(ClientError::NotAvailableOnLightClient) } fn last_finalized(&self) -> ClientResult<Block::Hash> { @@ -180,24 +156,23 @@ impl<S, F, Block> BlockchainBackend<Block> for Blockchain<S, F> where Block: Blo } fn leaves(&self) -> ClientResult<Vec<Block::Hash>> { - unimplemented!() + Err(ClientError::NotAvailableOnLightClient) } fn children(&self, _parent_hash: Block::Hash) -> ClientResult<Vec<Block::Hash>> { - unimplemented!() + Err(ClientError::NotAvailableOnLightClient) } } -impl<S: Storage<Block>, F, Block: BlockT> ProvideCache<Block> for Blockchain<S, F> { +impl<S: Storage<Block>, Block: BlockT> ProvideCache<Block> for Blockchain<S> { fn cache(&self) -> Option<Arc<dyn BlockchainCache<Block>>> { self.storage.cache() } } -impl<S, F, Block: BlockT> RemoteBlockchain<Block> for Blockchain<S, F> +impl<S, Block: BlockT> RemoteBlockchain<Block> for Blockchain<S> where S: Storage<Block>, - F: Fetcher<Block> + Send + Sync, { fn header(&self, id: BlockId<Block>) -> ClientResult<LocalOrRemote< Block::Header, @@ -253,12 +228,12 @@ pub fn future_header<Block: BlockT, F: Fetcher<Block>>( #[cfg(test)] pub mod tests { use std::collections::HashMap; + use parking_lot::Mutex; use test_client::runtime::{Hash, Block, Header}; use crate::blockchain::Info; - use crate::light::fetcher::tests::OkCallFetcher; use super::*; - pub type DummyBlockchain = Blockchain<DummyStorage, OkCallFetcher>; + pub type DummyBlockchain = Blockchain<DummyStorage>; pub struct DummyStorage { pub changes_tries_cht_roots: HashMap<u64, Hash>, diff --git a/core/client/src/light/call_executor.rs b/core/client/src/light/call_executor.rs index ab7b5b0a108b01352478033202bbbffee057badb..a06b48a6411a0b2d748a8745b1b2d4f62c381dff 100644 --- a/core/client/src/light/call_executor.rs +++ b/core/client/src/light/call_executor.rs @@ -14,17 +14,16 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see <http://www.gnu.org/licenses/>. -//! Light client call executor. Executes methods on remote full nodes, fetching -//! execution proof and checking it locally. +//! Methods that light client could use to execute runtime calls. use std::{ collections::HashSet, sync::Arc, panic::UnwindSafe, result, - marker::PhantomData, cell::RefCell, rc::Rc, + cell::RefCell, rc::Rc, }; use codec::{Encode, Decode}; use primitives::{ - offchain::{self, NeverOffchainExt}, H256, Blake2Hasher, convert_hash, NativeOrEncoded, + offchain, H256, Blake2Hasher, convert_hash, NativeOrEncoded, traits::CodeExecutor, }; use sr_primitives::generic::BlockId; @@ -37,211 +36,40 @@ use hash_db::Hasher; use crate::runtime_api::{ProofRecorder, InitializeBlock}; use crate::backend::RemoteBackend; -use crate::blockchain::Backend as ChainBackend; use crate::call_executor::CallExecutor; use crate::error::{Error as ClientError, Result as ClientResult}; -use crate::light::fetcher::{Fetcher, RemoteCallRequest}; +use crate::light::fetcher::RemoteCallRequest; use executor::{RuntimeVersion, NativeVersion}; -/// Call executor that executes methods on remote node, querying execution proof -/// and checking proof by re-executing locally. -pub struct RemoteCallExecutor<B, F> { - blockchain: Arc<B>, - fetcher: Arc<F>, -} - -/// Remote or local call executor. +/// Call executor that is able to execute calls only on genesis state. /// -/// Calls are executed locally if state is available locally. Otherwise, calls -/// are redirected to remote call executor. -pub struct RemoteOrLocalCallExecutor<Block: BlockT<Hash=H256>, B, R, L> { +/// Trying to execute call on non-genesis state leads to error. +pub struct GenesisCallExecutor<B, L> { backend: Arc<B>, - remote: R, local: L, - _block: PhantomData<Block>, } -impl<B, F> Clone for RemoteCallExecutor<B, F> { - fn clone(&self) -> Self { - RemoteCallExecutor { - blockchain: self.blockchain.clone(), - fetcher: self.fetcher.clone(), - } - } -} - -impl<B, F> RemoteCallExecutor<B, F> { - /// Creates new instance of remote call executor. - pub fn new(blockchain: Arc<B>, fetcher: Arc<F>) -> Self { - RemoteCallExecutor { blockchain, fetcher } - } -} - -impl<B, F, Block> CallExecutor<Block, Blake2Hasher> for RemoteCallExecutor<B, F> -where - Block: BlockT<Hash=H256>, - B: ChainBackend<Block>, - F: Fetcher<Block>, - Block::Hash: Ord, -{ - type Error = ClientError; - - fn call< - O: offchain::Externalities, - >( - &self, - id: &BlockId<Block>, - method: &str, - call_data: &[u8], - _strategy: ExecutionStrategy, - _side_effects_handler: Option<&mut O>, - ) -> ClientResult<Vec<u8>> - { - let block_hash = self.blockchain.expect_block_hash_from_id(id)?; - let block_header = self.blockchain.expect_header(id.clone())?; - - futures03::executor::block_on(self.fetcher.remote_call(RemoteCallRequest { - block: block_hash, - header: block_header, - method: method.into(), - call_data: call_data.to_vec(), - retry_count: None, - })) - } - - fn contextual_call< - 'a, - O: offchain::Externalities, - IB: Fn() -> ClientResult<()>, - EM: Fn( - Result<NativeOrEncoded<R>, Self::Error>, - Result<NativeOrEncoded<R>, Self::Error> - ) -> Result<NativeOrEncoded<R>, Self::Error>, - R: Encode + Decode + PartialEq, - NC, - >( - &self, - _initialize_block_fn: IB, - at: &BlockId<Block>, - method: &str, - call_data: &[u8], - changes: &RefCell<OverlayedChanges>, - initialize_block: InitializeBlock<'a, Block>, - execution_manager: ExecutionManager<EM>, - _native_call: Option<NC>, - side_effects_handler: Option<&mut O>, - _recorder: &Option<Rc<RefCell<ProofRecorder<Block>>>>, - _enable_keystore: bool, - ) -> ClientResult<NativeOrEncoded<R>> where ExecutionManager<EM>: Clone { - let block_initialized = match initialize_block { - InitializeBlock::Do(ref init_block) => { - init_block.borrow().is_some() - }, - InitializeBlock::Skip => false, - }; - - // it is only possible to execute contextual call if changes are empty - if !changes.borrow().is_empty() || block_initialized { - return Err(ClientError::NotAvailableOnLightClient.into()); - } - - self.call( - at, - method, - call_data, - (&execution_manager).into(), - side_effects_handler, - ).map(NativeOrEncoded::Encoded) - } - - fn runtime_version(&self, id: &BlockId<Block>) -> ClientResult<RuntimeVersion> { - let call_result = self.call( - id, - "Core_version", - &[], - ExecutionStrategy::NativeElseWasm, - NeverOffchainExt::new() - )?; - RuntimeVersion::decode(&mut call_result.as_slice()) - .map_err(|_| ClientError::VersionInvalid.into()) - } - - fn call_at_state< - O: offchain::Externalities, - S: StateBackend<Blake2Hasher>, - FF: FnOnce( - Result<NativeOrEncoded<R>, Self::Error>, - Result<NativeOrEncoded<R>, Self::Error> - ) -> Result<NativeOrEncoded<R>, Self::Error>, - R: Encode + Decode + PartialEq, - NC: FnOnce() -> result::Result<R, &'static str>, - >(&self, - _state: &S, - _changes: &mut OverlayedChanges, - _method: &str, - _call_data: &[u8], - _m: ExecutionManager<FF>, - _native_call: Option<NC>, - _side_effects_handler: Option<&mut O>, - ) -> ClientResult<( - NativeOrEncoded<R>, - (S::Transaction, <Blake2Hasher as Hasher>::Out), - Option<ChangesTrieTransaction<Blake2Hasher, NumberFor<Block>>>, - )> { - Err(ClientError::NotAvailableOnLightClient.into()) - } - - fn prove_at_trie_state<S: state_machine::TrieBackendStorage<Blake2Hasher>>( - &self, - _state: &state_machine::TrieBackend<S, Blake2Hasher>, - _changes: &mut OverlayedChanges, - _method: &str, - _call_data: &[u8] - ) -> ClientResult<(Vec<u8>, Vec<Vec<u8>>)> { - Err(ClientError::NotAvailableOnLightClient.into()) - } - - fn native_runtime_version(&self) -> Option<&NativeVersion> { - None +impl<B, L> GenesisCallExecutor<B, L> { + /// Create new genesis call executor. + pub fn new(backend: Arc<B>, local: L) -> Self { + Self { backend, local } } } -impl<Block, B, R, L> Clone for RemoteOrLocalCallExecutor<Block, B, R, L> - where - Block: BlockT<Hash=H256>, - B: RemoteBackend<Block, Blake2Hasher>, - R: CallExecutor<Block, Blake2Hasher> + Clone, - L: CallExecutor<Block, Blake2Hasher> + Clone, -{ +impl<B, L: Clone> Clone for GenesisCallExecutor<B, L> { fn clone(&self) -> Self { - RemoteOrLocalCallExecutor { + GenesisCallExecutor { backend: self.backend.clone(), - remote: self.remote.clone(), local: self.local.clone(), - _block: Default::default(), } } } -impl<Block, B, Remote, Local> RemoteOrLocalCallExecutor<Block, B, Remote, Local> +impl<Block, B, Local> CallExecutor<Block, Blake2Hasher> for + GenesisCallExecutor<B, Local> where Block: BlockT<Hash=H256>, B: RemoteBackend<Block, Blake2Hasher>, - Remote: CallExecutor<Block, Blake2Hasher>, - Local: CallExecutor<Block, Blake2Hasher>, -{ - /// Creates new instance of remote/local call executor. - pub fn new(backend: Arc<B>, remote: Remote, local: Local) -> Self { - RemoteOrLocalCallExecutor { backend, remote, local, _block: Default::default(), } - } -} - -impl<Block, B, Remote, Local> CallExecutor<Block, Blake2Hasher> for - RemoteOrLocalCallExecutor<Block, B, Remote, Local> - where - Block: BlockT<Hash=H256>, - B: RemoteBackend<Block, Blake2Hasher>, - Remote: CallExecutor<Block, Blake2Hasher>, Local: CallExecutor<Block, Blake2Hasher>, { type Error = ClientError; @@ -258,7 +86,7 @@ impl<Block, B, Remote, Local> CallExecutor<Block, Blake2Hasher> for ) -> ClientResult<Vec<u8>> { match self.backend.is_local_state_available(id) { true => self.local.call(id, method, call_data, strategy, side_effects_handler), - false => self.remote.call(id, method, call_data, strategy, side_effects_handler), + false => Err(ClientError::NotAvailableOnLightClient), } } @@ -313,36 +141,14 @@ impl<Block, B, Remote, Local> CallExecutor<Block, Blake2Hasher> for recorder, enable_keystore, ).map_err(|e| ClientError::Execution(Box::new(e.to_string()))), - false => CallExecutor::contextual_call::< - _, - _, - fn( - Result<NativeOrEncoded<R>, Remote::Error>, - Result<NativeOrEncoded<R>, Remote::Error>, - ) -> Result<NativeOrEncoded<R>, Remote::Error>, - _, - NC - >( - &self.remote, - initialize_block_fn, - at, - method, - call_data, - changes, - initialize_block, - ExecutionManager::NativeWhenPossible, - native_call, - side_effects_handler, - recorder, - enable_keystore, - ).map_err(|e| ClientError::Execution(Box::new(e.to_string()))), + false => Err(ClientError::NotAvailableOnLightClient), } } fn runtime_version(&self, id: &BlockId<Block>) -> ClientResult<RuntimeVersion> { match self.backend.is_local_state_available(id) { true => self.local.runtime_version(id), - false => self.remote.runtime_version(id), + false => Err(ClientError::NotAvailableOnLightClient), } } @@ -356,50 +162,29 @@ impl<Block, B, Remote, Local> CallExecutor<Block, Blake2Hasher> for R: Encode + Decode + PartialEq, NC: FnOnce() -> result::Result<R, &'static str> + UnwindSafe, >(&self, - state: &S, - changes: &mut OverlayedChanges, - method: &str, - call_data: &[u8], + _state: &S, + _changes: &mut OverlayedChanges, + _method: &str, + _call_data: &[u8], _manager: ExecutionManager<FF>, - native_call: Option<NC>, - side_effects_handler: Option<&mut O>, + _native_call: Option<NC>, + _side_effects_handler: Option<&mut O>, ) -> ClientResult<( NativeOrEncoded<R>, (S::Transaction, <Blake2Hasher as Hasher>::Out), Option<ChangesTrieTransaction<Blake2Hasher, NumberFor<Block>>>, )> { - // there's no actual way/need to specify native/wasm execution strategy on light node - // => we can safely ignore passed values - - CallExecutor::call_at_state::< - _, - _, - fn( - Result<NativeOrEncoded<R>, Remote::Error>, - Result<NativeOrEncoded<R>, Remote::Error>, - ) -> Result<NativeOrEncoded<R>, Remote::Error>, - _, - NC - >( - &self.remote, - state, - changes, - method, - call_data, - ExecutionManager::NativeWhenPossible, - native_call, - side_effects_handler, - ).map_err(|e| ClientError::Execution(Box::new(e.to_string()))) + Err(ClientError::NotAvailableOnLightClient) } fn prove_at_trie_state<S: state_machine::TrieBackendStorage<Blake2Hasher>>( &self, - state: &state_machine::TrieBackend<S, Blake2Hasher>, - changes: &mut OverlayedChanges, - method: &str, - call_data: &[u8] + _state: &state_machine::TrieBackend<S, Blake2Hasher>, + _changes: &mut OverlayedChanges, + _method: &str, + _call_data: &[u8] ) -> ClientResult<(Vec<u8>, Vec<Vec<u8>>)> { - self.remote.prove_at_trie_state(state, changes, method, call_data) + Err(ClientError::NotAvailableOnLightClient) } fn native_runtime_version(&self) -> Option<&NativeVersion> { @@ -517,13 +302,103 @@ fn check_execution_proof_with_make_header<Header, E, H, MakeNextHeader: Fn(&Head #[cfg(test)] mod tests { use consensus::BlockOrigin; - use test_client::{self, runtime::{Header, Digest}, ClientExt, TestClient}; + use primitives::offchain::NeverOffchainExt; + use test_client::{self, runtime::{Header, Digest, Block}, ClientExt, TestClient}; use executor::NativeExecutor; use crate::backend::{Backend, NewBlockState}; use crate::in_mem::Backend as InMemBackend; - use crate::light::fetcher::tests::OkCallFetcher; use super::*; + struct DummyCallExecutor; + + impl CallExecutor<Block, Blake2Hasher> for DummyCallExecutor { + type Error = ClientError; + + fn call<O: offchain::Externalities>( + &self, + _id: &BlockId<Block>, + _method: &str, + _call_data: &[u8], + _strategy: ExecutionStrategy, + _side_effects_handler: Option<&mut O>, + ) -> Result<Vec<u8>, ClientError> { + Ok(vec![42]) + } + + fn contextual_call< + 'a, + O: offchain::Externalities, + IB: Fn() -> ClientResult<()>, + EM: Fn( + Result<NativeOrEncoded<R>, Self::Error>, + Result<NativeOrEncoded<R>, Self::Error> + ) -> Result<NativeOrEncoded<R>, Self::Error>, + R: Encode + Decode + PartialEq, + NC: FnOnce() -> result::Result<R, &'static str> + UnwindSafe, + >( + &self, + _initialize_block_fn: IB, + _at: &BlockId<Block>, + _method: &str, + _call_data: &[u8], + _changes: &RefCell<OverlayedChanges>, + _initialize_block: InitializeBlock<'a, Block>, + _execution_manager: ExecutionManager<EM>, + _native_call: Option<NC>, + _side_effects_handler: Option<&mut O>, + _proof_recorder: &Option<Rc<RefCell<ProofRecorder<Block>>>>, + _enable_keystore: bool, + ) -> ClientResult<NativeOrEncoded<R>> where ExecutionManager<EM>: Clone { + unreachable!() + } + + fn runtime_version(&self, _id: &BlockId<Block>) -> Result<RuntimeVersion, ClientError> { + unreachable!() + } + + fn call_at_state< + O: offchain::Externalities, + S: state_machine::Backend<Blake2Hasher>, + F: FnOnce( + Result<NativeOrEncoded<R>, Self::Error>, + Result<NativeOrEncoded<R>, Self::Error> + ) -> Result<NativeOrEncoded<R>, Self::Error>, + R: Encode + Decode + PartialEq, + NC: FnOnce() -> result::Result<R, &'static str> + UnwindSafe, + >(&self, + _state: &S, + _overlay: &mut OverlayedChanges, + _method: &str, + _call_data: &[u8], + _manager: ExecutionManager<F>, + _native_call: Option<NC>, + _side_effects_handler: Option<&mut O>, + ) -> Result< + ( + NativeOrEncoded<R>, + (S::Transaction, H256), + Option<ChangesTrieTransaction<Blake2Hasher, NumberFor<Block>>>, + ), + ClientError, + > { + unreachable!() + } + + fn prove_at_trie_state<S: state_machine::TrieBackendStorage<Blake2Hasher>>( + &self, + _trie_state: &state_machine::TrieBackend<S, Blake2Hasher>, + _overlay: &mut OverlayedChanges, + _method: &str, + _call_data: &[u8] + ) -> Result<(Vec<u8>, Vec<Vec<u8>>), ClientError> { + unreachable!() + } + + fn native_runtime_version(&self) -> Option<&NativeVersion> { + unreachable!() + } + } + #[test] fn execution_proof_is_generated_and_checked() { fn execute(remote_client: &TestClient, at: u64, method: &'static str) -> (Vec<u8>, Vec<u8>) { @@ -624,8 +499,8 @@ mod tests { } #[test] - fn code_is_executed_locally_or_remotely() { - let backend = Arc::new(InMemBackend::new()); + fn code_is_executed_at_genesis_only() { + let backend = Arc::new(InMemBackend::<Block, Blake2Hasher>::new()); let def = H256::default(); let header0 = test_client::runtime::Header::new(0, def, def, def, Default::default()); let hash0 = header0.hash(); @@ -634,34 +509,29 @@ mod tests { backend.blockchain().insert(hash0, header0, None, None, NewBlockState::Final).unwrap(); backend.blockchain().insert(hash1, header1, None, None, NewBlockState::Final).unwrap(); - let local_executor = RemoteCallExecutor::new( - Arc::new(backend.blockchain().clone()), - Arc::new(OkCallFetcher::new(vec![1])), - ); - let remote_executor = RemoteCallExecutor::new( - Arc::new(backend.blockchain().clone()), - Arc::new(OkCallFetcher::new(vec![2])), - ); - let remote_or_local = RemoteOrLocalCallExecutor::new(backend, remote_executor, local_executor); + let genesis_executor = GenesisCallExecutor::new(backend, DummyCallExecutor); assert_eq!( - remote_or_local.call( + genesis_executor.call( &BlockId::Number(0), "test_method", &[], ExecutionStrategy::NativeElseWasm, NeverOffchainExt::new(), ).unwrap(), - vec![1], + vec![42], ); - assert_eq!( - remote_or_local.call( - &BlockId::Number(1), - "test_method", - &[], - ExecutionStrategy::NativeElseWasm, - NeverOffchainExt::new(), - ).unwrap(), - vec![2], + + let call_on_unavailable = genesis_executor.call( + &BlockId::Number(1), + "test_method", + &[], + ExecutionStrategy::NativeElseWasm, + NeverOffchainExt::new(), ); + + match call_on_unavailable { + Err(ClientError::NotAvailableOnLightClient) => (), + _ => unreachable!("unexpected result: {:?}", call_on_unavailable), + } } } diff --git a/core/client/src/light/fetcher.rs b/core/client/src/light/fetcher.rs index 6ac637f3fa078c9e04fbceefe46c0655d430f9cd..c25092c32c1f17528958ab535e0e6eabd8eeb323 100644 --- a/core/client/src/light/fetcher.rs +++ b/core/client/src/light/fetcher.rs @@ -221,15 +221,15 @@ pub trait FetchChecker<Block: BlockT>: Send + Sync { } /// Remote data checker. -pub struct LightDataChecker<E, H, B: BlockT, S: BlockchainStorage<B>, F> { - blockchain: Arc<Blockchain<S, F>>, +pub struct LightDataChecker<E, H, B: BlockT, S: BlockchainStorage<B>> { + blockchain: Arc<Blockchain<S>>, executor: E, _hasher: PhantomData<(B, H)>, } -impl<E, H, B: BlockT, S: BlockchainStorage<B>, F> LightDataChecker<E, H, B, S, F> { +impl<E, H, B: BlockT, S: BlockchainStorage<B>> LightDataChecker<E, H, B, S> { /// Create new light data checker. - pub fn new(blockchain: Arc<Blockchain<S, F>>, executor: E) -> Self { + pub fn new(blockchain: Arc<Blockchain<S>>, executor: E) -> Self { Self { blockchain, executor, _hasher: PhantomData } @@ -367,14 +367,13 @@ impl<E, H, B: BlockT, S: BlockchainStorage<B>, F> LightDataChecker<E, H, B, S, F } } -impl<E, Block, H, S, F> FetchChecker<Block> for LightDataChecker<E, H, Block, S, F> +impl<E, Block, H, S> FetchChecker<Block> for LightDataChecker<E, H, Block, S> where Block: BlockT, E: CodeExecutor<H>, H: Hasher, H::Out: Ord + 'static, S: BlockchainStorage<Block>, - F: Send + Sync, { fn check_header_proof( &self, @@ -563,7 +562,6 @@ pub mod tests { Blake2Hasher, Block, DummyStorage, - OkCallFetcher, >; fn prepare_for_read_proof_check() -> (TestChecker, Header, Vec<Vec<u8>>, u32) { diff --git a/core/client/src/light/mod.rs b/core/client/src/light/mod.rs index 08e14ad8f323bb75015fcc03e7139a07f78e94d1..03b7dcff8564c45d7d9102b1a41a68531d1484fa 100644 --- a/core/client/src/light/mod.rs +++ b/core/client/src/light/mod.rs @@ -33,55 +33,48 @@ use crate::client::Client; use crate::error::Result as ClientResult; use crate::light::backend::Backend; use crate::light::blockchain::{Blockchain, Storage as BlockchainStorage}; -use crate::light::call_executor::{RemoteCallExecutor, RemoteOrLocalCallExecutor}; -use crate::light::fetcher::{Fetcher, LightDataChecker}; +use crate::light::call_executor::GenesisCallExecutor; +use crate::light::fetcher::LightDataChecker; /// Create an instance of light client blockchain backend. -pub fn new_light_blockchain<B: BlockT, S: BlockchainStorage<B>, F>(storage: S) -> Arc<Blockchain<S, F>> { +pub fn new_light_blockchain<B: BlockT, S: BlockchainStorage<B>>(storage: S) -> Arc<Blockchain<S>> { Arc::new(Blockchain::new(storage)) } /// Create an instance of light client backend. -pub fn new_light_backend<B, S, F>(blockchain: Arc<Blockchain<S, F>>, fetcher: Arc<F>) -> Arc<Backend<S, F, Blake2Hasher>> +pub fn new_light_backend<B, S>(blockchain: Arc<Blockchain<S>>) -> Arc<Backend<S, Blake2Hasher>> where B: BlockT, S: BlockchainStorage<B>, - F: Fetcher<B>, { - blockchain.set_fetcher(Arc::downgrade(&fetcher)); Arc::new(Backend::new(blockchain)) } /// Create an instance of light client. -pub fn new_light<B, S, F, GS, RA, E>( - backend: Arc<Backend<S, F, Blake2Hasher>>, - fetcher: Arc<F>, +pub fn new_light<B, S, GS, RA, E>( + backend: Arc<Backend<S, Blake2Hasher>>, genesis_storage: GS, code_executor: E, -) -> ClientResult<Client<Backend<S, F, Blake2Hasher>, RemoteOrLocalCallExecutor< - B, - Backend<S, F, Blake2Hasher>, - RemoteCallExecutor<Blockchain<S, F>, F>, - LocalCallExecutor<Backend<S, F, Blake2Hasher>, E> +) -> ClientResult<Client<Backend<S, Blake2Hasher>, GenesisCallExecutor< + Backend<S, Blake2Hasher>, + LocalCallExecutor<Backend<S, Blake2Hasher>, E> >, B, RA>> where B: BlockT<Hash=H256>, S: BlockchainStorage<B> + 'static, - F: Fetcher<B> + 'static, GS: BuildStorage, E: CodeExecutor<Blake2Hasher> + RuntimeInfo, { - let remote_executor = RemoteCallExecutor::new(backend.blockchain().clone(), fetcher); let local_executor = LocalCallExecutor::new(backend.clone(), code_executor, None); - let executor = RemoteOrLocalCallExecutor::new(backend.clone(), remote_executor, local_executor); + let executor = GenesisCallExecutor::new(backend.clone(), local_executor); Client::new(backend, executor, genesis_storage, Default::default()) } /// Create an instance of fetch data checker. -pub fn new_fetch_checker<E, B: BlockT, S: BlockchainStorage<B>, F>( - blockchain: Arc<Blockchain<S, F>>, +pub fn new_fetch_checker<E, B: BlockT, S: BlockchainStorage<B>>( + blockchain: Arc<Blockchain<S>>, executor: E, -) -> LightDataChecker<E, Blake2Hasher, B, S, F> +) -> LightDataChecker<E, Blake2Hasher, B, S> where E: CodeExecutor<Blake2Hasher>, { diff --git a/core/service/src/builder.rs b/core/service/src/builder.rs index 1540eeac9cdb6d83508725499410bb218dc80a15..458c72a74ff6dc0cfe379eec37bfd618adfbe6ae 100644 --- a/core/service/src/builder.rs +++ b/core/service/src/builder.rs @@ -108,29 +108,18 @@ type TLightClient<TBl, TRtApi, TExecDisp> = Client< /// Light client backend type. type TLightBackend<TBl> = client::light::backend::Backend< client_db::light::LightStorage<TBl>, - network::OnDemand<TBl>, Blake2Hasher, >; /// Light call executor type. -type TLightCallExecutor<TBl, TExecDisp> = client::light::call_executor::RemoteOrLocalCallExecutor< - TBl, +type TLightCallExecutor<TBl, TExecDisp> = client::light::call_executor::GenesisCallExecutor< client::light::backend::Backend< client_db::light::LightStorage<TBl>, - network::OnDemand<TBl>, Blake2Hasher >, - client::light::call_executor::RemoteCallExecutor< - client::light::blockchain::Blockchain< - client_db::light::LightStorage<TBl>, - network::OnDemand<TBl> - >, - network::OnDemand<TBl>, - >, client::LocalCallExecutor< client::light::backend::Backend< client_db::light::LightStorage<TBl>, - network::OnDemand<TBl>, Blake2Hasher >, NativeExecutor<TExecDisp> @@ -240,11 +229,10 @@ where TGen: Serialize + DeserializeOwned + BuildStorage { let light_blockchain = client::light::new_light_blockchain(db_storage); let fetch_checker = Arc::new(client::light::new_fetch_checker(light_blockchain.clone(), executor.clone())); let fetcher = Arc::new(network::OnDemand::new(fetch_checker)); - let backend = client::light::new_light_backend(light_blockchain, fetcher.clone()); + let backend = client::light::new_light_backend(light_blockchain); let remote_blockchain = backend.remote_blockchain(); let client = Arc::new(client::light::new_light( backend.clone(), - fetcher.clone(), &config.chain_spec, executor, )?); @@ -459,15 +447,22 @@ impl<TBl, TRtApi, TCfg, TGen, TCl, TFchr, TSc, TImpQu, TFprb, TFpp, TNetP, TExPo /// Defines which import queue to use. pub fn with_import_queue_and_opt_fprb<UImpQu, UFprb>( self, - builder: impl FnOnce(&Configuration<TCfg, TGen>, Arc<TCl>, Arc<Backend>, Option<TSc>, Arc<TExPool>) - -> Result<(UImpQu, Option<UFprb>), Error> + builder: impl FnOnce( + &Configuration<TCfg, TGen>, + Arc<TCl>, + Arc<Backend>, + Option<TFchr>, + Option<TSc>, + Arc<TExPool>, + ) -> Result<(UImpQu, Option<UFprb>), Error> ) -> Result<ServiceBuilder<TBl, TRtApi, TCfg, TGen, TCl, TFchr, TSc, UImpQu, UFprb, TFpp, TNetP, TExPool, TRpc, TRpcB, Backend>, Error> - where TSc: Clone { + where TSc: Clone, TFchr: Clone { let (import_queue, fprb) = builder( &self.config, self.client.clone(), self.backend.clone(), + self.fetcher.clone(), self.select_chain.clone(), self.transaction_pool.clone() )?; @@ -494,12 +489,21 @@ impl<TBl, TRtApi, TCfg, TGen, TCl, TFchr, TSc, TImpQu, TFprb, TFpp, TNetP, TExPo /// Defines which import queue to use. pub fn with_import_queue_and_fprb<UImpQu, UFprb>( self, - builder: impl FnOnce(&Configuration<TCfg, TGen>, Arc<TCl>, Arc<Backend>, Option<TSc>, Arc<TExPool>) - -> Result<(UImpQu, UFprb), Error> + builder: impl FnOnce( + &Configuration<TCfg, TGen>, + Arc<TCl>, + Arc<Backend>, + Option<TFchr>, + Option<TSc>, + Arc<TExPool>, + ) -> Result<(UImpQu, UFprb), Error> ) -> Result<ServiceBuilder<TBl, TRtApi, TCfg, TGen, TCl, TFchr, TSc, UImpQu, UFprb, TFpp, TNetP, TExPool, TRpc, TRpcB, Backend>, Error> - where TSc: Clone { - self.with_import_queue_and_opt_fprb(|cfg, cl, b, sc, tx| builder(cfg, cl, b, sc, tx).map(|(q, f)| (q, Some(f)))) + where TSc: Clone, TFchr: Clone { + self.with_import_queue_and_opt_fprb(|cfg, cl, b, f, sc, tx| + builder(cfg, cl, b, f, sc, tx) + .map(|(q, f)| (q, Some(f))) + ) } /// Defines which transaction pool to use. diff --git a/core/test-client/src/lib.rs b/core/test-client/src/lib.rs index 17e26708468aab7afca1e648c17c5c81ca83289d..3ae999f1f16fafe20eb72dc657256d8b165c0c50 100644 --- a/core/test-client/src/lib.rs +++ b/core/test-client/src/lib.rs @@ -47,7 +47,6 @@ use client::LocalCallExecutor; /// Test client light database backend. pub type LightBackend<Block> = client::light::backend::Backend< client_db::light::LightStorage<Block>, - LightFetcher, Blake2Hasher, >; diff --git a/core/test-runtime/client/src/lib.rs b/core/test-runtime/client/src/lib.rs index aeed1e7ad447e069a420650c97e46983d806b0dd..229fcbdaf9072279ad7f3d848b896b8e65117824 100644 --- a/core/test-runtime/client/src/lib.rs +++ b/core/test-runtime/client/src/lib.rs @@ -73,20 +73,11 @@ pub type Executor = client::LocalCallExecutor< pub type LightBackend = generic_test_client::LightBackend<runtime::Block>; /// Test client light executor. -pub type LightExecutor = client::light::call_executor::RemoteOrLocalCallExecutor< - runtime::Block, +pub type LightExecutor = client::light::call_executor::GenesisCallExecutor< LightBackend, - client::light::call_executor::RemoteCallExecutor< - client::light::blockchain::Blockchain< - client_db::light::LightStorage<runtime::Block>, - LightFetcher - >, - LightFetcher - >, client::LocalCallExecutor< client::light::backend::Backend< client_db::light::LightStorage<runtime::Block>, - LightFetcher, Blake2Hasher >, NativeExecutor<LocalExecutor> @@ -271,22 +262,16 @@ pub fn new_light() -> ( let blockchain = Arc::new(client::light::blockchain::Blockchain::new(storage)); let backend = Arc::new(LightBackend::new(blockchain.clone())); let executor = NativeExecutor::new(None); - let fetcher = Arc::new(LightFetcher); - let remote_call_executor = client::light::call_executor::RemoteCallExecutor::new( - blockchain.clone(), - fetcher, - ); let local_call_executor = client::LocalCallExecutor::new(backend.clone(), executor, None); let call_executor = LightExecutor::new( backend.clone(), - remote_call_executor, local_call_executor, ); - (TestClientBuilder::with_backend(backend.clone()) - .build_with_executor(call_executor) - .0, - backend, + ( + TestClientBuilder::with_backend(backend.clone()) + .build_with_executor(call_executor) + .0, + backend, ) - } diff --git a/node-template/src/service.rs b/node-template/src/service.rs index 310b8f44a7cfc897d993864391d7485c658e7884..f4ab3f40000e2b71c8f88c17aeb062d4d77c38d9 100644 --- a/node-template/src/service.rs +++ b/node-template/src/service.rs @@ -197,9 +197,8 @@ pub fn new_light<C: Send + Default + 'static>(config: Configuration<C, GenesisCo .with_transaction_pool(|config, client| Ok(TransactionPool::new(config, transaction_pool::ChainApi::new(client))) )? - .with_import_queue_and_fprb(|_config, client, backend, _select_chain, transaction_pool| { - let fetch_checker = backend.blockchain().fetcher() - .upgrade() + .with_import_queue_and_fprb(|_config, client, backend, fetcher, _select_chain, transaction_pool| { + let fetch_checker = fetcher .map(|fetcher| fetcher.checker().clone()) .ok_or_else(|| "Trying to start light import queue without active fetch checker")?; let block_import = grandpa::light_block_import::<_, _, _, RuntimeApi, _>( diff --git a/node/cli/src/service.rs b/node/cli/src/service.rs index ca6b249484e07f85ef1b049252ff7e0339249aca..f3ce9baa2e353875bc8be460ab6081bd2e616e7f 100644 --- a/node/cli/src/service.rs +++ b/node/cli/src/service.rs @@ -237,9 +237,8 @@ pub fn new_light<C: Send + Default + 'static>(config: Configuration<C, GenesisCo .with_transaction_pool(|config, client| Ok(TransactionPool::new(config, transaction_pool::ChainApi::new(client))) )? - .with_import_queue_and_fprb(|_config, client, backend, _select_chain, transaction_pool| { - let fetch_checker = backend.blockchain().fetcher() - .upgrade() + .with_import_queue_and_fprb(|_config, client, backend, fetcher, _select_chain, transaction_pool| { + let fetch_checker = fetcher .map(|fetcher| fetcher.checker().clone()) .ok_or_else(|| "Trying to start light import queue without active fetch checker")?; let block_import = grandpa::light_block_import::<_, _, _, RuntimeApi, _>(