// 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 . //! Substrate Client data backend use std::sync::Arc; use std::collections::HashMap; use sp_core::ChangesTrieConfigurationRange; use sp_core::offchain::OffchainStorage; use sp_runtime::{generic::BlockId, Justification, Storage}; use sp_runtime::traits::{Block as BlockT, NumberFor, HashFor}; 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 }, light::RemoteBlockchain, UsageInfo, }; use sp_blockchain; 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; /// Extracts the transaction for the given state backend. pub type TransactionForSB = >>::Transaction; /// Extracts the transaction for the given backend. pub type TransactionFor = TransactionForSB, Block>; /// Import operation summary. /// /// Contains information about the block that just got imported, /// including storage changes, reorged blocks, etc. pub struct ImportSummary { /// Block hash of the imported block. pub hash: Block::Hash, /// Import origin. pub origin: BlockOrigin, /// Header of the imported block. pub header: Block::Header, /// Is this block a new best block. pub is_new_best: bool, /// Optional storage changes. pub storage_changes: Option<(StorageCollection, ChildStorageCollection)>, /// Blocks that got retracted because of this one got imported. pub retracted: Vec, } /// Import operation wrapper pub struct ClientImportOperation> { /// DB Operation. pub op: B::BlockImportOperation, /// Summary of imported block. pub notify_imported: Option>, /// A list of hashes of blocks that got finalized. pub notify_finalized: Vec, } /// State of a new block. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum NewBlockState { /// Normal block. Normal, /// New best block. Best, /// Newly finalized block (implicitly best). Final, } impl NewBlockState { /// Whether this block is the new best block. pub fn is_best(self) -> bool { match self { NewBlockState::Best | NewBlockState::Final => true, NewBlockState::Normal => false, } } /// Whether this block is considered final. pub fn is_final(self) -> bool { match self { NewBlockState::Final => true, NewBlockState::Best | NewBlockState::Normal => false, } } } /// Block insertion operation. /// /// Keeps hold if the inserted block state and data. pub trait BlockImportOperation { /// Associated state backend type. type State: StateBackend>; /// Returns pending state. /// /// Returns None for backends with locally-unavailable state data. fn state(&self) -> sp_blockchain::Result>; /// Append block data to the transaction. fn set_block_data( &mut self, header: Block::Header, body: Option>, justification: Option, state: NewBlockState, ) -> sp_blockchain::Result<()>; /// Update cached data. fn update_cache(&mut self, cache: HashMap>); /// Inject storage data into the database. fn update_db_storage( &mut self, update: TransactionForSB, ) -> sp_blockchain::Result<()>; /// Inject storage data into the database replacing any existing data. fn reset_storage(&mut self, storage: Storage) -> sp_blockchain::Result; /// Set storage changes. fn update_storage( &mut self, update: StorageCollection, child_update: ChildStorageCollection, ) -> sp_blockchain::Result<()>; /// Inject changes trie data into the database. fn update_changes_trie( &mut self, update: ChangesTrieTransaction, NumberFor>, ) -> sp_blockchain::Result<()>; /// Insert auxiliary keys. /// /// Values are `None` if should be deleted. fn insert_aux(&mut self, ops: I) -> sp_blockchain::Result<()> where I: IntoIterator, Option>)>; /// Mark a block as finalized. fn mark_finalized( &mut self, id: BlockId, justification: Option, ) -> sp_blockchain::Result<()>; /// Mark a block as new head. If both block import and set head are specified, set head /// overrides block import's best block rule. fn mark_head(&mut self, id: BlockId) -> sp_blockchain::Result<()>; } /// Interface for performing operations on the backend. pub trait LockImportRun> { /// Lock the import lock, and run operations inside. fn lock_import_and_run(&self, f: F) -> Result where F: FnOnce(&mut ClientImportOperation) -> Result, Err: From; } /// Finalize Facilities pub trait Finalizer> { /// Mark all blocks up to given as finalized in operation. /// /// If `justification` is provided it is stored with the given finalized /// block (any other finalized blocks are left unjustified). /// /// If the block being finalized is on a different fork from the current /// best block the finalized block is set as best, this might be slightly /// inaccurate (i.e. outdated). Usages that require determining an accurate /// best block should use `SelectChain` instead of the client. fn apply_finality( &self, operation: &mut ClientImportOperation, id: BlockId, justification: Option, notify: bool, ) -> sp_blockchain::Result<()>; /// Finalize a block. /// /// This will implicitly finalize all blocks up to it and /// fire finality notifications. /// /// If the block being finalized is on a different fork from the current /// best block, the finalized block is set as best. This might be slightly /// inaccurate (i.e. outdated). Usages that require determining an accurate /// best block should use `SelectChain` instead of the client. /// /// Pass a flag to indicate whether finality notifications should be propagated. /// This is usually tied to some synchronization state, where we don't send notifications /// while performing major synchronization work. fn finalize_block( &self, id: BlockId, justification: Option, notify: bool, ) -> sp_blockchain::Result<()>; } /// Provides access to an auxiliary database. pub trait AuxStore { /// Insert auxiliary data into key-value store. /// /// Deletions occur after insertions. fn insert_aux< 'a, 'b: 'a, 'c: 'a, I: IntoIterator, D: IntoIterator, >(&self, insert: I, delete: D) -> sp_blockchain::Result<()>; /// Query auxiliary data from key-value store. 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. /// /// Note on state pruning: while an object from `state_at` is alive, the state /// should not be pruned. The backend should internally reference-count /// its state objects. /// /// The same applies for live `BlockImportOperation`s: while an import operation building on a /// parent `P` is alive, the state for `P` should not be pruned. pub trait Backend: AuxStore + Send + Sync { /// Associated block insertion operation type. type BlockImportOperation: BlockImportOperation; /// Associated blockchain backend type. type Blockchain: BlockchainBackend; /// Associated state backend type. type State: StateBackend> + Send; /// Offchain workers local storage. type OffchainStorage: OffchainStorage; /// Begin a new block insertion transaction with given parent block id. /// /// When constructing the genesis, this is called with all-zero hash. fn begin_operation(&self) -> sp_blockchain::Result; /// Note an operation to contain state transition. fn begin_state_operation( &self, operation: &mut Self::BlockImportOperation, block: BlockId, ) -> sp_blockchain::Result<()>; /// Commit block insertion. fn commit_operation(&self, transaction: Self::BlockImportOperation) -> sp_blockchain::Result<()>; /// Finalize block with given Id. /// /// This should only be called if the parent of the given block has been finalized. fn finalize_block( &self, block: BlockId, justification: Option, ) -> sp_blockchain::Result<()>; /// Returns reference to blockchain backend. fn blockchain(&self) -> &Self::Blockchain; /// Returns current usage statistics. fn usage_info(&self) -> Option; /// Returns reference to changes trie storage. fn changes_trie_storage(&self) -> Option<&dyn PrunableStateChangesTrieStorage>; /// Returns a handle to offchain storage. fn offchain_storage(&self) -> Option; /// Returns true if state for given block is available. fn have_state_at(&self, hash: &Block::Hash, _number: NumberFor) -> bool { self.state_at(BlockId::Hash(hash.clone())).is_ok() } /// Returns state backend with post-state of given block. fn state_at(&self, block: BlockId) -> sp_blockchain::Result; /// Attempts to revert the chain by `n` blocks. If `revert_finalized` is set /// it will attempt to revert past any finalized block, this is unsafe and /// can potentially leave the node in an inconsistent state. /// /// Returns the number of blocks that were successfully reverted. fn revert( &self, n: NumberFor, revert_finalized: bool, ) -> sp_blockchain::Result>; /// Insert auxiliary data into key-value store. fn insert_aux< 'a, 'b: 'a, 'c: 'a, I: IntoIterator, D: IntoIterator, >(&self, insert: I, delete: D) -> sp_blockchain::Result<()> { AuxStore::insert_aux(self, insert, delete) } /// Query auxiliary data from key-value store. fn get_aux(&self, key: &[u8]) -> sp_blockchain::Result>> { AuxStore::get_aux(self, key) } /// Gain access to the import lock around this backend. /// /// _Note_ Backend isn't expected to acquire the lock by itself ever. Rather /// the using components should acquire and hold the lock whenever they do /// something that the import of a block would interfere with, e.g. importing /// a new block or calculating the best head. fn get_import_lock(&self) -> &RwLock<()>; } /// Changes trie storage that supports pruning. pub trait PrunableStateChangesTrieStorage: StateChangesTrieStorage, NumberFor> { /// Get reference to StateChangesTrieStorage. fn storage(&self) -> &dyn StateChangesTrieStorage, NumberFor>; /// Get configuration at given block. fn configuration_at(&self, at: &BlockId) -> sp_blockchain::Result< ChangesTrieConfigurationRange, Block::Hash> >; /// Get end block (inclusive) of oldest pruned max-level (or skewed) digest trie blocks range. /// It is guaranteed that we have no any changes tries before (and including) this block. /// It is guaranteed that all existing changes tries after this block are not yet pruned (if created). fn oldest_pruned_digest_range_end(&self) -> NumberFor; } /// Mark for all Backend implementations, that are making use of state data, stored locally. pub trait LocalBackend: Backend {} /// Mark for all Backend implementations, that are fetching required state data from remote nodes. pub trait RemoteBackend: Backend { /// Returns true if the state for given block is available locally. fn is_local_state_available(&self, block: &BlockId) -> bool; /// Returns reference to blockchain backend. /// /// Returned backend either resolves blockchain data /// locally, or prepares request to fetch that data from remote node. fn remote_blockchain(&self) -> Arc>; } /// Return changes tries state at given block. pub fn changes_tries_state_at_block<'a, Block: BlockT>( block: &BlockId, maybe_storage: Option<&'a dyn PrunableStateChangesTrieStorage>, ) -> sp_blockchain::Result, NumberFor>>> { let storage = match maybe_storage { Some(storage) => storage, None => return Ok(None), }; let config_range = storage.configuration_at(block)?; match config_range.config { Some(config) => Ok(Some(ChangesTrieState::new(config, config_range.zero.0, storage.storage()))), None => Ok(None), } }