// This file is part of Substrate. // Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program 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. // This program 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 this program. If not, see . //! Longest chain implementation use sc_client_api::backend; use sp_blockchain::{Backend, HeaderBackend}; use sp_consensus::{Error as ConsensusError, SelectChain}; use sp_runtime::{ generic::BlockId, traits::{Block as BlockT, NumberFor}, }; use std::{marker::PhantomData, sync::Arc}; /// Implement Longest Chain Select implementation /// where 'longest' is defined as the highest number of blocks pub struct LongestChain { backend: Arc, _phantom: PhantomData, } impl Clone for LongestChain { fn clone(&self) -> Self { let backend = self.backend.clone(); LongestChain { backend, _phantom: Default::default() } } } impl LongestChain where B: backend::Backend, Block: BlockT, { /// Instantiate a new LongestChain for Backend B pub fn new(backend: Arc) -> Self { LongestChain { backend, _phantom: Default::default() } } fn best_block_header(&self) -> sp_blockchain::Result<::Header> { let info = self.backend.blockchain().info(); let import_lock = self.backend.get_import_lock(); let best_hash = self .backend .blockchain() .best_containing(info.best_hash, None, import_lock)? .unwrap_or(info.best_hash); Ok(self .backend .blockchain() .header(BlockId::Hash(best_hash))? .expect("given block hash was fetched from block in db; qed")) } fn leaves(&self) -> Result::Hash>, sp_blockchain::Error> { self.backend.blockchain().leaves() } } #[async_trait::async_trait] impl SelectChain for LongestChain where B: backend::Backend, Block: BlockT, { async fn leaves(&self) -> Result::Hash>, ConsensusError> { LongestChain::leaves(self).map_err(|e| ConsensusError::ChainLookup(e.to_string())) } async fn best_chain(&self) -> Result<::Header, ConsensusError> { LongestChain::best_block_header(self) .map_err(|e| ConsensusError::ChainLookup(e.to_string())) } async fn finality_target( &self, target_hash: Block::Hash, maybe_max_number: Option>, ) -> Result { let import_lock = self.backend.get_import_lock(); self.backend .blockchain() .best_containing(target_hash, maybe_max_number, import_lock) .map(|maybe_hash| maybe_hash.unwrap_or(target_hash)) .map_err(|e| ConsensusError::ChainLookup(e.to_string())) } }