// Copyright 2019-2020 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // Substrate is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . //! Substrate light client interfaces use std::sync::Arc; use std::collections::{BTreeMap, HashMap}; use std::future::Future; use sp_runtime::{ traits::{ Block as BlockT, Header as HeaderT, NumberFor, }, generic::BlockId }; use sp_core::ChangesTrieConfigurationRange; use sp_state_machine::StorageProof; use sp_blockchain::{ HeaderMetadata, well_known_cache_keys, HeaderBackend, Cache as BlockchainCache, Error as ClientError, Result as ClientResult, }; use crate::{backend::{AuxStore, NewBlockState}, UsageInfo}; /// Remote call request. #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct RemoteCallRequest { /// Call at state of given block. pub block: Header::Hash, /// Header of block at which call is performed. pub header: Header, /// Method to call. pub method: String, /// Call data. pub call_data: Vec, /// Number of times to retry request. None means that default RETRY_COUNT is used. pub retry_count: Option, } /// Remote canonical header request. #[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] pub struct RemoteHeaderRequest { /// The root of CHT this block is included in. pub cht_root: Header::Hash, /// Number of the header to query. pub block: Header::Number, /// Number of times to retry request. None means that default RETRY_COUNT is used. pub retry_count: Option, } /// Remote storage read request. #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct RemoteReadRequest { /// Read at state of given block. pub block: Header::Hash, /// Header of block at which read is performed. pub header: Header, /// Storage key to read. pub keys: Vec>, /// Number of times to retry request. None means that default RETRY_COUNT is used. pub retry_count: Option, } /// Remote storage read child request. #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct RemoteReadChildRequest { /// Read at state of given block. pub block: Header::Hash, /// Header of block at which read is performed. pub header: Header, /// Storage key for child. pub storage_key: Vec, /// Child trie source information. pub child_info: Vec, /// Child type, its required to resolve `child_info` /// content and choose child implementation. pub child_type: u32, /// Child storage key to read. pub keys: Vec>, /// Number of times to retry request. None means that default RETRY_COUNT is used. pub retry_count: Option, } /// Remote key changes read request. #[derive(Clone, Debug, PartialEq, Eq)] pub struct RemoteChangesRequest { /// All changes trie configurations that are valid within [first_block; last_block]. pub changes_trie_configs: Vec>, /// Query changes from range of blocks, starting (and including) with this hash... pub first_block: (Header::Number, Header::Hash), /// ...ending (and including) with this hash. Should come after first_block and /// be the part of the same fork. pub last_block: (Header::Number, Header::Hash), /// Only use digests from blocks up to this hash. Should be last_block OR come /// after this block and be the part of the same fork. pub max_block: (Header::Number, Header::Hash), /// Known changes trie roots for the range of blocks [tries_roots.0..max_block]. /// Proofs for roots of ascendants of tries_roots.0 are provided by the remote node. pub tries_roots: (Header::Number, Header::Hash, Vec), /// Optional Child Storage key to read. pub storage_key: Option>, /// Storage key to read. pub key: Vec, /// Number of times to retry request. None means that default RETRY_COUNT is used. pub retry_count: Option, } /// Key changes read proof. #[derive(Debug, PartialEq, Eq)] pub struct ChangesProof { /// Max block that has been used in changes query. pub max_block: Header::Number, /// All touched nodes of all changes tries. pub proof: Vec>, /// All changes tries roots that have been touched AND are missing from /// the requester' node. It is a map of block number => changes trie root. pub roots: BTreeMap, /// The proofs for all changes tries roots that have been touched AND are /// missing from the requester' node. It is a map of CHT number => proof. pub roots_proof: StorageProof, } /// Remote block body request #[derive(Clone, Default, Debug, PartialEq, Eq, Hash)] pub struct RemoteBodyRequest { /// Header of the requested block body pub header: Header, /// Number of times to retry request. None means that default RETRY_COUNT is used. pub retry_count: Option, } /// Light client data fetcher. Implementations of this trait must check if remote data /// is correct (see FetchedDataChecker) and return already checked data. pub trait Fetcher: Send + Sync { /// Remote header future. type RemoteHeaderResult: Future> + Unpin + Send + 'static; /// Remote storage read future. type RemoteReadResult: Future, Option>>, ClientError, >> + Unpin + Send + 'static; /// Remote call result future. type RemoteCallResult: Future, ClientError, >> + Unpin + Send + 'static; /// Remote changes result future. type RemoteChangesResult: Future, u32)>, ClientError, >> + Unpin + Send + 'static; /// Remote block body result future. type RemoteBodyResult: Future, ClientError, >> + Unpin + Send + 'static; /// Fetch remote header. fn remote_header(&self, request: RemoteHeaderRequest) -> Self::RemoteHeaderResult; /// Fetch remote storage value. fn remote_read( &self, request: RemoteReadRequest ) -> Self::RemoteReadResult; /// Fetch remote storage child value. fn remote_read_child( &self, request: RemoteReadChildRequest ) -> Self::RemoteReadResult; /// Fetch remote call result. fn remote_call(&self, request: RemoteCallRequest) -> Self::RemoteCallResult; /// Fetch remote changes ((block number, extrinsic index)) where given key has been changed /// at a given blocks range. fn remote_changes(&self, request: RemoteChangesRequest) -> Self::RemoteChangesResult; /// Fetch remote block body fn remote_body(&self, request: RemoteBodyRequest) -> Self::RemoteBodyResult; } /// Light client remote data checker. /// /// Implementations of this trait should not use any prunable blockchain data /// except that is passed to its methods. pub trait FetchChecker: Send + Sync { /// Check remote header proof. fn check_header_proof( &self, request: &RemoteHeaderRequest, header: Option, remote_proof: StorageProof, ) -> ClientResult; /// Check remote storage read proof. fn check_read_proof( &self, request: &RemoteReadRequest, remote_proof: StorageProof, ) -> ClientResult, Option>>>; /// Check remote storage read proof. fn check_read_child_proof( &self, request: &RemoteReadChildRequest, remote_proof: StorageProof, ) -> ClientResult, Option>>>; /// Check remote method execution proof. fn check_execution_proof( &self, request: &RemoteCallRequest, remote_proof: StorageProof, ) -> ClientResult>; /// Check remote changes query proof. fn check_changes_proof( &self, request: &RemoteChangesRequest, proof: ChangesProof ) -> ClientResult, u32)>>; /// Check remote body proof. fn check_body_proof( &self, request: &RemoteBodyRequest, body: Vec ) -> ClientResult>; } /// Light client blockchain storage. pub trait Storage: AuxStore + HeaderBackend + HeaderMetadata { /// Store new header. Should refuse to revert any finalized blocks. /// /// Takes new authorities, the leaf state of the new block, and /// any auxiliary storage updates to place in the same operation. fn import_header( &self, header: Block::Header, cache: HashMap>, state: NewBlockState, aux_ops: Vec<(Vec, Option>)>, ) -> ClientResult<()>; /// Set an existing block as new best block. fn set_head(&self, block: BlockId) -> ClientResult<()>; /// Mark historic header as finalized. fn finalize_header(&self, block: BlockId) -> ClientResult<()>; /// Get last finalized header. fn last_finalized(&self) -> ClientResult; /// Get headers CHT root for given block. Returns None if the block is not pruned (not a part of any CHT). fn header_cht_root( &self, cht_size: NumberFor, block: NumberFor, ) -> ClientResult>; /// Get changes trie CHT root for given block. Returns None if the block is not pruned (not a part of any CHT). fn changes_trie_cht_root( &self, cht_size: NumberFor, block: NumberFor, ) -> ClientResult>; /// Get storage cache. fn cache(&self) -> Option>>; /// Get storage usage statistics. fn usage_info(&self) -> Option; } /// Remote header. #[derive(Debug)] pub enum LocalOrRemote { /// When data is available locally, it is returned. Local(Data), /// When data is unavailable locally, the request to fetch it from remote node is returned. Remote(Request), /// When data is unknown. Unknown, } /// Futures-based blockchain backend that either resolves blockchain data /// locally, or fetches required data from remote node. pub trait RemoteBlockchain: Send + Sync { /// Get block header. fn header(&self, id: BlockId) -> ClientResult, >>; } #[cfg(test)] pub mod tests { use futures::future::Ready; use parking_lot::Mutex; use sp_blockchain::Error as ClientError; use sp_test_primitives::{Block, Header, Extrinsic}; use super::*; pub type OkCallFetcher = Mutex>; fn not_implemented_in_tests() -> Ready> where E: std::convert::From<&'static str>, { futures::future::ready(Err("Not implemented on test node".into())) } impl Fetcher for OkCallFetcher { type RemoteHeaderResult = Ready>; type RemoteReadResult = Ready, Option>>, ClientError>>; type RemoteCallResult = Ready, ClientError>>; type RemoteChangesResult = Ready, u32)>, ClientError>>; type RemoteBodyResult = Ready, ClientError>>; fn remote_header(&self, _request: RemoteHeaderRequest
) -> Self::RemoteHeaderResult { not_implemented_in_tests() } fn remote_read(&self, _request: RemoteReadRequest
) -> Self::RemoteReadResult { not_implemented_in_tests() } fn remote_read_child(&self, _request: RemoteReadChildRequest
) -> Self::RemoteReadResult { not_implemented_in_tests() } fn remote_call(&self, _request: RemoteCallRequest
) -> Self::RemoteCallResult { futures::future::ready(Ok((*self.lock()).clone())) } fn remote_changes(&self, _request: RemoteChangesRequest
) -> Self::RemoteChangesResult { not_implemented_in_tests() } fn remote_body(&self, _request: RemoteBodyRequest
) -> Self::RemoteBodyResult { not_implemented_in_tests() } } }