// Copyright 2017-2019 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 crate::error; use crate::light::blockchain::RemoteBlockchain; use primitives::ChangesTrieConfiguration; use sr_primitives::{generic::BlockId, Justification, StorageOverlay, ChildrenStorageOverlay}; use sr_primitives::traits::{Block as BlockT, NumberFor}; use state_machine::backend::Backend as StateBackend; use state_machine::{ChangesTrieStorage as StateChangesTrieStorage, ChangesTrieTransaction}; use crate::blockchain::well_known_cache_keys; use consensus::BlockOrigin; use hash_db::Hasher; use parking_lot::Mutex; /// In memory array of storage values. pub type StorageCollection = Vec<(Vec, Option>)>; /// In memory arrays of storage values for multiple child tries. pub type ChildStorageCollection = Vec<(Vec, StorageCollection)>; pub(crate) struct ImportSummary { pub(crate) hash: Block::Hash, pub(crate) origin: BlockOrigin, pub(crate) header: Block::Header, pub(crate) is_new_best: bool, pub(crate) storage_changes: Option<(StorageCollection, ChildStorageCollection)>, pub(crate) retracted: Vec, } /// Import operation wrapper pub struct ClientImportOperation< Block: BlockT, H: Hasher, B: Backend, > { pub(crate) op: B::BlockImportOperation, pub(crate) notify_imported: Option>, pub(crate) 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 where Block: BlockT, H: Hasher, { /// Associated state backend type. type State: StateBackend; /// Returns pending state. Returns None for backends with locally-unavailable state data. fn state(&self) -> error::Result>; /// Append block data to the transaction. fn set_block_data( &mut self, header: Block::Header, body: Option>, justification: Option, state: NewBlockState, ) -> error::Result<()>; /// Update cached data. fn update_cache(&mut self, cache: HashMap>); /// Inject storage data into the database. fn update_db_storage(&mut self, update: >::Transaction) -> error::Result<()>; /// Inject storage data into the database replacing any existing data. fn reset_storage(&mut self, top: StorageOverlay, children: ChildrenStorageOverlay) -> error::Result; /// Set storage changes. fn update_storage( &mut self, update: StorageCollection, child_update: ChildStorageCollection, ) -> error::Result<()>; /// Inject changes trie data into the database. fn update_changes_trie(&mut self, update: ChangesTrieTransaction>) -> error::Result<()>; /// Insert auxiliary keys. Values are `None` if should be deleted. fn insert_aux(&mut self, ops: I) -> error::Result<()> where I: IntoIterator, Option>)>; /// Mark a block as finalized. fn mark_finalized(&mut self, id: BlockId, justification: Option) -> error::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) -> error::Result<()>; } /// Finalize Facilities pub trait Finalizer, B: Backend> { /// Mark all blocks up to given as finalized in operation. If a /// 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, ) -> error::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, ) -> error::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) -> error::Result<()>; /// Query auxiliary data from key-value store. fn get_aux(&self, key: &[u8]) -> error::Result>>; } /// 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 where Block: BlockT, H: Hasher, { /// Associated block insertion operation type. type BlockImportOperation: BlockImportOperation; /// Associated blockchain backend type. type Blockchain: crate::blockchain::Backend; /// Associated state backend type. type State: StateBackend; /// Changes trie storage. type ChangesTrieStorage: PrunableStateChangesTrieStorage; /// 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) -> error::Result; /// Note an operation to contain state transition. fn begin_state_operation(&self, operation: &mut Self::BlockImportOperation, block: BlockId) -> error::Result<()>; /// Commit block insertion. fn commit_operation(&self, transaction: Self::BlockImportOperation) -> error::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) -> error::Result<()>; /// Returns reference to blockchain backend. fn blockchain(&self) -> &Self::Blockchain; /// Returns the used state cache, if existent. fn used_state_cache_size(&self) -> Option; /// Returns reference to changes trie storage. fn changes_trie_storage(&self) -> Option<&Self::ChangesTrieStorage>; /// 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) -> error::Result; /// Destroy state and save any useful data, such as cache. fn destroy_state(&self, _state: Self::State) -> error::Result<()> { Ok(()) } /// Attempts to revert the chain by `n` blocks. Returns the number of blocks that were /// successfully reverted. fn revert(&self, n: NumberFor) -> error::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) -> error::Result<()> { AuxStore::insert_aux(self, insert, delete) } /// Query auxiliary data from key-value store. fn get_aux(&self, key: &[u8]) -> error::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) -> &Mutex<()>; } /// Offchain workers local storage. pub trait OffchainStorage: Clone + Send + Sync { /// Persist a value in storage under given key and prefix. fn set(&mut self, prefix: &[u8], key: &[u8], value: &[u8]); /// Retrieve a value from storage under given key and prefix. fn get(&self, prefix: &[u8], key: &[u8]) -> Option>; /// Replace the value in storage if given old_value matches the current one. /// /// Returns `true` if the value has been set and false otherwise. fn compare_and_set( &mut self, prefix: &[u8], key: &[u8], old_value: Option<&[u8]>, new_value: &[u8], ) -> bool; } /// Changes trie storage that supports pruning. pub trait PrunableStateChangesTrieStorage: StateChangesTrieStorage> { /// Get number block of oldest, non-pruned changes trie. fn oldest_changes_trie_block( &self, config: &ChangesTrieConfiguration, best_finalized: NumberFor, ) -> NumberFor; } /// Mark for all Backend implementations, that are making use of state data, stored locally. pub trait LocalBackend: Backend where Block: BlockT, H: Hasher, {} /// Mark for all Backend implementations, that are fetching required state data from remote nodes. pub trait RemoteBackend: Backend where Block: BlockT, H: Hasher, { /// 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 that either resolves blockchain data /// locally, or prepares request to fetch that data from remote node. fn remote_blockchain(&self) -> Arc>; }