use std::sync::Arc; use sp_core::crypto::KeyTypeId; use sp_inherents::CreateInherentDataProviders; use sp_runtime::traits::{Header, Block}; use sp_blockchain::HeaderBackend; use sp_api::{StateBackend, StateBackendFor, TransactionFor, ApiExt, ProvideRuntimeApi}; use sp_consensus::{Error, Environment}; use sc_client_api::{BlockBackend, Backend, Finalizer, BlockchainEvents}; use sc_block_builder::BlockBuilderApi; use sc_consensus::{BlockImport, BasicQueue}; use sc_network_common::config::NonDefaultSetConfig; use sc_network::{ProtocolName, NetworkBlock}; use sc_network_gossip::Network; use sp_tendermint::TendermintApi; use substrate_prometheus_endpoint::Registry; mod validators; pub(crate) mod tendermint; pub use tendermint::TendermintImport; mod block_import; pub use block_import::TendermintSelectChain; pub(crate) mod authority; pub use authority::TendermintAuthority; pub const CONSENSUS_ID: [u8; 4] = *b"tend"; pub(crate) const KEY_TYPE_ID: KeyTypeId = KeyTypeId(CONSENSUS_ID); const PROTOCOL_NAME: &str = "/tendermint/1"; pub fn protocol_name>(genesis: Hash, fork: Option<&str>) -> ProtocolName { let mut name = format!("/{}", hex::encode(genesis.as_ref())); if let Some(fork) = fork { name += &format!("/{fork}"); } name += PROTOCOL_NAME; name.into() } pub fn set_config(protocol: ProtocolName, block_size: u64) -> NonDefaultSetConfig { // The extra 512 bytes is for the additional data part of Tendermint // Even with BLS, that should just be 161 bytes in the worst case, for a perfect messaging scheme // While 256 bytes would suffice there, it's unknown if any LibP2P overhead exists nor if // anything here will be perfect. Considering this is miniscule compared to the block size, it's // better safe than sorry. let mut cfg = NonDefaultSetConfig::new(protocol, block_size + 512); cfg.allow_non_reserved(25, 25); cfg } /// Trait consolidating all generics required by sc_tendermint for processing. pub trait TendermintClient: Send + Sync + 'static { const PROPOSED_BLOCK_SIZE_LIMIT: usize; const BLOCK_PROCESSING_TIME_IN_SECONDS: u32; const LATENCY_TIME_IN_SECONDS: u32; type Block: Block; type Backend: Backend + 'static; /// TransactionFor type BackendTransaction: Send + Sync + 'static; /// StateBackendFor type StateBackend: StateBackend< <::Header as Header>::Hashing, Transaction = Self::BackendTransaction, >; // Client::Api type Api: ApiExt + BlockBuilderApi + TendermintApi; type Client: Send + Sync + HeaderBackend + BlockBackend + BlockImport + Finalizer + BlockchainEvents + ProvideRuntimeApi + 'static; } /// Trait implementable on firm types to automatically provide a full TendermintClient impl. pub trait TendermintClientMinimal: Send + Sync + 'static { const PROPOSED_BLOCK_SIZE_LIMIT: usize; const BLOCK_PROCESSING_TIME_IN_SECONDS: u32; const LATENCY_TIME_IN_SECONDS: u32; type Block: Block; type Backend: Backend + 'static; type Api: ApiExt + BlockBuilderApi + TendermintApi; type Client: Send + Sync + HeaderBackend + BlockBackend + BlockImport> + Finalizer + BlockchainEvents + ProvideRuntimeApi + 'static; } impl TendermintClient for T where >::Api: BlockBuilderApi + TendermintApi, TransactionFor: Send + Sync + 'static, { const PROPOSED_BLOCK_SIZE_LIMIT: usize = T::PROPOSED_BLOCK_SIZE_LIMIT; const BLOCK_PROCESSING_TIME_IN_SECONDS: u32 = T::BLOCK_PROCESSING_TIME_IN_SECONDS; const LATENCY_TIME_IN_SECONDS: u32 = T::LATENCY_TIME_IN_SECONDS; type Block = T::Block; type Backend = T::Backend; type BackendTransaction = TransactionFor; type StateBackend = StateBackendFor; type Api = >::Api; type Client = T::Client; } /// Trait consolidating additional generics required by sc_tendermint for authoring. pub trait TendermintValidator: TendermintClient { type CIDP: CreateInherentDataProviders + 'static; type Environment: Send + Sync + Environment + 'static; type Network: Clone + Send + Sync + Network + NetworkBlock<::Hash, <::Header as Header>::Number> + 'static; } pub type TendermintImportQueue = BasicQueue; /// Create an import queue, additionally returning the Tendermint Import object iself, enabling /// creating an author later as well. pub fn import_queue( spawner: &impl sp_core::traits::SpawnEssentialNamed, client: Arc, registry: Option<&Registry>, ) -> (TendermintImport, TendermintImportQueue) where Arc: BlockImport, as BlockImport>::Error: Into, { let import = TendermintImport::::new(client); let boxed = Box::new(import.clone()); // Use None for the justification importer since justifications always come with blocks // Therefore, they're never imported after the fact, which is what mandates an importer let queue = || BasicQueue::new(import.clone(), boxed.clone(), None, spawner, registry); *futures::executor::block_on(import.queue.write()) = Some(queue()); (import.clone(), queue()) }