diff --git a/substrate/node/src/service.rs b/substrate/node/src/service.rs index 0feba075..e0aa7e4b 100644 --- a/substrate/node/src/service.rs +++ b/substrate/node/src/service.rs @@ -1,7 +1,4 @@ -use std::{ - sync::{Arc, RwLock}, - future::Future, -}; +use std::sync::{Arc, RwLock}; use sp_core::H256; @@ -11,7 +8,9 @@ use sc_network::{NetworkService, NetworkBlock}; use sc_telemetry::{Telemetry, TelemetryWorker}; use serai_runtime::{self, opaque::Block, RuntimeApi}; -pub(crate) use serai_consensus::{ExecutorDispatch, Announce, FullClient}; +pub(crate) use serai_consensus::{ + TendermintAuthority, ExecutorDispatch, Announce, FullClient, TendermintValidatorFirm, +}; type FullBackend = sc_service::TFullBackend; type FullSelectChain = serai_consensus::TendermintSelectChain; @@ -42,7 +41,13 @@ impl Announce for NetworkAnnounce { pub fn new_partial( config: &Configuration, -) -> Result<((NetworkAnnounce, impl Future), PartialComponents), ServiceError> { +) -> Result< + ( + (NetworkAnnounce, TendermintAuthority>), + PartialComponents, + ), + ServiceError, +> { if config.keystore_remote.is_some() { return Err(ServiceError::Other("Remote Keystores are not supported".to_string())); } @@ -179,7 +184,7 @@ pub async fn new_full(config: Configuration) -> Result BlockImport for TendermintImport +impl BlockImport for TendermintImport where Arc: BlockImport, as BlockImport>::Error: Into, diff --git a/substrate/tendermint/client/src/import_queue.rs b/substrate/tendermint/client/src/import_queue.rs index aaf7e282..8e3fac01 100644 --- a/substrate/tendermint/client/src/import_queue.rs +++ b/substrate/tendermint/client/src/import_queue.rs @@ -1,32 +1,22 @@ use std::{ - convert::TryInto, pin::Pin, sync::{Arc, RwLock}, task::{Poll, Context}, future::Future, - time::{UNIX_EPOCH, SystemTime}, }; -use sp_core::Decode; use sp_runtime::traits::{Header, Block}; -use sp_api::BlockId; use sp_consensus::Error; use sc_consensus::{BlockImportStatus, BlockImportError, BlockImport, Link, BasicQueue}; use sc_service::ImportQueue; -use sc_client_api::{HeaderBackend, BlockBackend}; use substrate_prometheus_endpoint::Registry; -use tendermint_machine::{ - ext::{BlockNumber, Commit}, - TendermintMachine, -}; - use crate::{ - CONSENSUS_ID, types::TendermintAuthor, validators::TendermintValidators, - tendermint::TendermintImport, + types::TendermintValidator, + tendermint::{TendermintImport, TendermintAuthority}, }; pub type TendermintImportQueue = BasicQueue; @@ -77,54 +67,20 @@ impl<'a, B: Block, T: Send> Future for ImportFuture<'a, B, T> { } } -pub fn import_queue( +pub fn import_queue( client: Arc, announce: T::Announce, providers: Arc, env: T::Environment, spawner: &impl sp_core::traits::SpawnEssentialNamed, registry: Option<&Registry>, -) -> (impl Future, TendermintImportQueue) +) -> (TendermintAuthority, TendermintImportQueue) where Arc: BlockImport, as BlockImport>::Error: Into, { let import = TendermintImport::::new(client, announce, providers, env); - - let authority = { - let machine_clone = import.machine.clone(); - let mut import_clone = import.clone(); - let best = import.client.info().best_number; - async move { - *machine_clone.write().unwrap() = Some(TendermintMachine::new( - import_clone.clone(), - // TODO - 0, - ( - // Header::Number: TryInto doesn't implement Debug and can't be unwrapped - match TryInto::::try_into(best) { - Ok(best) => BlockNumber(best + 1), - Err(_) => panic!("BlockNumber exceeded u64"), - }, - Commit::>::decode( - &mut import_clone - .client - .justifications(&BlockId::Number(best)) - .unwrap() - .map(|justifications| justifications.get(CONSENSUS_ID).cloned().unwrap()) - .unwrap_or_default() - .as_ref(), - ) - .map(|commit| commit.end_time) - // TODO: Genesis start time - .unwrap_or_else(|_| SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs()), - ), - import_clone - .get_proposal(&import_clone.client.header(BlockId::Number(0u8.into())).unwrap().unwrap()) - .await, - )); - } - }; + let authority = TendermintAuthority(import.clone()); let boxed = Box::new(import.clone()); // Use None for the justification importer since justifications always come with blocks diff --git a/substrate/tendermint/client/src/lib.rs b/substrate/tendermint/client/src/lib.rs index 0a552eb0..3343a3fd 100644 --- a/substrate/tendermint/client/src/lib.rs +++ b/substrate/tendermint/client/src/lib.rs @@ -1,4 +1,4 @@ -use std::{marker::PhantomData, boxed::Box, sync::Arc, future::Future, error::Error}; +use std::{marker::PhantomData, boxed::Box, sync::Arc, error::Error}; use sp_runtime::traits::Block as BlockTrait; use sp_inherents::CreateInherentDataProviders; @@ -14,11 +14,12 @@ use substrate_prometheus_endpoint::Registry; use serai_runtime::{self, opaque::Block, RuntimeApi}; mod types; -use types::{TendermintClientMinimal, TendermintAuthor}; +use types::{TendermintClientMinimal, TendermintValidator}; mod validators; mod tendermint; +pub use tendermint::TendermintAuthority; mod block_import; mod verifier; @@ -54,7 +55,7 @@ pub trait Announce: Send + Sync + Clone + 'static { fn announce(&self, hash: B::Hash); } -struct Cidp; +pub struct Cidp; #[async_trait::async_trait] impl CreateInherentDataProviders for Cidp { type InherentDataProviders = (sp_timestamp::InherentDataProvider,); @@ -67,15 +68,15 @@ impl CreateInherentDataProviders for Cidp { } } -struct TendermintAuthorFirm>(PhantomData); -impl> TendermintClientMinimal for TendermintAuthorFirm { +pub struct TendermintValidatorFirm>(PhantomData); +impl> TendermintClientMinimal for TendermintValidatorFirm { type Block = Block; type Backend = sc_client_db::Backend; type Api = >::Api; type Client = FullClient; } -impl> TendermintAuthor for TendermintAuthorFirm { +impl> TendermintValidator for TendermintValidatorFirm { type CIDP = Cidp; type Environment = sc_basic_authorship::ProposerFactory< FullPool, @@ -93,8 +94,11 @@ pub fn import_queue>( announce: A, pool: Arc>, registry: Option<&Registry>, -) -> (impl Future, TendermintImportQueue>) { - import_queue::import_queue::>( +) -> ( + TendermintAuthority>, + TendermintImportQueue>, +) { + import_queue::import_queue::>( client.clone(), announce, Arc::new(Cidp), diff --git a/substrate/tendermint/client/src/tendermint.rs b/substrate/tendermint/client/src/tendermint.rs index d40b67bd..f70e3c9a 100644 --- a/substrate/tendermint/client/src/tendermint.rs +++ b/substrate/tendermint/client/src/tendermint.rs @@ -1,7 +1,7 @@ use std::{ marker::PhantomData, sync::{Arc, RwLock}, - time::Duration, + time::{UNIX_EPOCH, SystemTime, Duration}, }; use async_trait::async_trait; @@ -23,22 +23,22 @@ use sp_consensus::{Error, BlockOrigin, Proposer, Environment}; use sc_consensus::{ForkChoiceStrategy, BlockImportParams, import_queue::IncomingBlock}; use sc_service::ImportQueue; -use sc_client_api::Finalizer; +use sc_client_api::{BlockBackend, Finalizer}; use tendermint_machine::{ - ext::{BlockError, Commit, Network}, - SignedMessage, TendermintHandle, + ext::{BlockError, BlockNumber, Commit, Network}, + SignedMessage, TendermintMachine, TendermintHandle, }; use crate::{ CONSENSUS_ID, - types::TendermintAuthor, + types::TendermintValidator, validators::TendermintValidators, import_queue::{ImportFuture, TendermintImportQueue}, Announce, }; -pub(crate) struct TendermintImport { +pub(crate) struct TendermintImport { _ta: PhantomData, validators: Arc>, @@ -55,7 +55,46 @@ pub(crate) struct TendermintImport { Arc>>>, } -impl Clone for TendermintImport { +pub struct TendermintAuthority(pub(crate) TendermintImport); +impl TendermintAuthority { + pub async fn validate(mut self) { + let info = self.0.client.info(); + + // Header::Number: TryInto doesn't implement Debug and can't be unwrapped + let start_number = match TryInto::::try_into(info.best_number) { + Ok(best) => BlockNumber(best + 1), + Err(_) => panic!("BlockNumber exceeded u64"), + }; + let start_time = Commit::>::decode( + &mut self + .0 + .client + .justifications(&BlockId::Hash(info.best_hash)) + .unwrap() + .map(|justifications| justifications.get(CONSENSUS_ID).cloned().unwrap()) + .unwrap_or_default() + .as_ref(), + ) + .map(|commit| commit.end_time) + // TODO: Genesis start time + .unwrap_or_else(|_| SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs()); + + let proposal = self + .0 + .get_proposal(&self.0.client.header(BlockId::Hash(info.best_hash)).unwrap().unwrap()) + .await; + + *self.0.machine.write().unwrap() = Some(TendermintMachine::new( + self.0.clone(), + // TODO + 0, // ValidatorId + (start_number, start_time), + proposal, + )); + } +} + +impl Clone for TendermintImport { fn clone(&self) -> Self { TendermintImport { _ta: PhantomData, @@ -75,7 +114,7 @@ impl Clone for TendermintImport { } } -impl TendermintImport { +impl TendermintImport { pub(crate) fn new( client: Arc, announce: T::Announce, @@ -254,7 +293,7 @@ impl TendermintImport { } #[async_trait] -impl Network for TendermintImport { +impl Network for TendermintImport { type ValidatorId = u16; type SignatureScheme = TendermintValidators; type Weights = TendermintValidators; diff --git a/substrate/tendermint/client/src/types.rs b/substrate/tendermint/client/src/types.rs index 0573a694..a21ae977 100644 --- a/substrate/tendermint/client/src/types.rs +++ b/substrate/tendermint/client/src/types.rs @@ -67,7 +67,7 @@ where } /// Trait consolidating additional generics required by sc_tendermint for authoring. -pub trait TendermintAuthor: TendermintClient { +pub trait TendermintValidator: TendermintClient { type CIDP: CreateInherentDataProviders + 'static; type Environment: Send + Sync + Environment + 'static; diff --git a/substrate/tendermint/client/src/verifier.rs b/substrate/tendermint/client/src/verifier.rs index d064a84f..9b7c2a92 100644 --- a/substrate/tendermint/client/src/verifier.rs +++ b/substrate/tendermint/client/src/verifier.rs @@ -5,10 +5,10 @@ use async_trait::async_trait; use sp_consensus::{Error, CacheKeyId}; use sc_consensus::{BlockImportParams, BlockImport, Verifier}; -use crate::{types::TendermintAuthor, tendermint::TendermintImport}; +use crate::{types::TendermintValidator, tendermint::TendermintImport}; #[async_trait] -impl Verifier for TendermintImport +impl Verifier for TendermintImport where Arc: BlockImport, as BlockImport>::Error: Into,