Remove the Future triggering the machine for an async fn

Enables passing data in, such as the network.
This commit is contained in:
Luke Parker
2022-10-30 04:08:33 -04:00
parent 6838d5c922
commit edb2e00db7
7 changed files with 82 additions and 78 deletions

View File

@@ -1,7 +1,4 @@
use std::{ use std::sync::{Arc, RwLock};
sync::{Arc, RwLock},
future::Future,
};
use sp_core::H256; use sp_core::H256;
@@ -11,7 +8,9 @@ use sc_network::{NetworkService, NetworkBlock};
use sc_telemetry::{Telemetry, TelemetryWorker}; use sc_telemetry::{Telemetry, TelemetryWorker};
use serai_runtime::{self, opaque::Block, RuntimeApi}; 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<Block>; type FullBackend = sc_service::TFullBackend<Block>;
type FullSelectChain = serai_consensus::TendermintSelectChain<Block, FullBackend>; type FullSelectChain = serai_consensus::TendermintSelectChain<Block, FullBackend>;
@@ -42,7 +41,13 @@ impl Announce<Block> for NetworkAnnounce {
pub fn new_partial( pub fn new_partial(
config: &Configuration, config: &Configuration,
) -> Result<((NetworkAnnounce, impl Future<Output = ()>), PartialComponents), ServiceError> { ) -> Result<
(
(NetworkAnnounce, TendermintAuthority<TendermintValidatorFirm<NetworkAnnounce>>),
PartialComponents,
),
ServiceError,
> {
if config.keystore_remote.is_some() { if config.keystore_remote.is_some() {
return Err(ServiceError::Other("Remote Keystores are not supported".to_string())); return Err(ServiceError::Other("Remote Keystores are not supported".to_string()));
} }
@@ -179,7 +184,7 @@ pub async fn new_full(config: Configuration) -> Result<TaskManager, ServiceError
})?; })?;
if is_authority { if is_authority {
authority.await; authority.validate().await;
} }
network_starter.start_network(); network_starter.start_network();

View File

@@ -5,10 +5,10 @@ use async_trait::async_trait;
use sp_consensus::{Error, CacheKeyId}; use sp_consensus::{Error, CacheKeyId};
use sc_consensus::{BlockCheckParams, BlockImportParams, ImportResult, BlockImport}; use sc_consensus::{BlockCheckParams, BlockImportParams, ImportResult, BlockImport};
use crate::{types::TendermintAuthor, tendermint::TendermintImport}; use crate::{types::TendermintValidator, tendermint::TendermintImport};
#[async_trait] #[async_trait]
impl<T: TendermintAuthor> BlockImport<T::Block> for TendermintImport<T> impl<T: TendermintValidator> BlockImport<T::Block> for TendermintImport<T>
where where
Arc<T::Client>: BlockImport<T::Block, Transaction = T::BackendTransaction>, Arc<T::Client>: BlockImport<T::Block, Transaction = T::BackendTransaction>,
<Arc<T::Client> as BlockImport<T::Block>>::Error: Into<Error>, <Arc<T::Client> as BlockImport<T::Block>>::Error: Into<Error>,

View File

@@ -1,32 +1,22 @@
use std::{ use std::{
convert::TryInto,
pin::Pin, pin::Pin,
sync::{Arc, RwLock}, sync::{Arc, RwLock},
task::{Poll, Context}, task::{Poll, Context},
future::Future, future::Future,
time::{UNIX_EPOCH, SystemTime},
}; };
use sp_core::Decode;
use sp_runtime::traits::{Header, Block}; use sp_runtime::traits::{Header, Block};
use sp_api::BlockId;
use sp_consensus::Error; use sp_consensus::Error;
use sc_consensus::{BlockImportStatus, BlockImportError, BlockImport, Link, BasicQueue}; use sc_consensus::{BlockImportStatus, BlockImportError, BlockImport, Link, BasicQueue};
use sc_service::ImportQueue; use sc_service::ImportQueue;
use sc_client_api::{HeaderBackend, BlockBackend};
use substrate_prometheus_endpoint::Registry; use substrate_prometheus_endpoint::Registry;
use tendermint_machine::{
ext::{BlockNumber, Commit},
TendermintMachine,
};
use crate::{ use crate::{
CONSENSUS_ID, types::TendermintAuthor, validators::TendermintValidators, types::TendermintValidator,
tendermint::TendermintImport, tendermint::{TendermintImport, TendermintAuthority},
}; };
pub type TendermintImportQueue<Block, Transaction> = BasicQueue<Block, Transaction>; pub type TendermintImportQueue<Block, Transaction> = BasicQueue<Block, Transaction>;
@@ -77,54 +67,20 @@ impl<'a, B: Block, T: Send> Future for ImportFuture<'a, B, T> {
} }
} }
pub fn import_queue<T: TendermintAuthor>( pub fn import_queue<T: TendermintValidator>(
client: Arc<T::Client>, client: Arc<T::Client>,
announce: T::Announce, announce: T::Announce,
providers: Arc<T::CIDP>, providers: Arc<T::CIDP>,
env: T::Environment, env: T::Environment,
spawner: &impl sp_core::traits::SpawnEssentialNamed, spawner: &impl sp_core::traits::SpawnEssentialNamed,
registry: Option<&Registry>, registry: Option<&Registry>,
) -> (impl Future<Output = ()>, TendermintImportQueue<T::Block, T::BackendTransaction>) ) -> (TendermintAuthority<T>, TendermintImportQueue<T::Block, T::BackendTransaction>)
where where
Arc<T::Client>: BlockImport<T::Block, Transaction = T::BackendTransaction>, Arc<T::Client>: BlockImport<T::Block, Transaction = T::BackendTransaction>,
<Arc<T::Client> as BlockImport<T::Block>>::Error: Into<Error>, <Arc<T::Client> as BlockImport<T::Block>>::Error: Into<Error>,
{ {
let import = TendermintImport::<T>::new(client, announce, providers, env); let import = TendermintImport::<T>::new(client, announce, providers, env);
let authority = TendermintAuthority(import.clone());
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<u64> doesn't implement Debug and can't be unwrapped
match TryInto::<u64>::try_into(best) {
Ok(best) => BlockNumber(best + 1),
Err(_) => panic!("BlockNumber exceeded u64"),
},
Commit::<TendermintValidators<T>>::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 boxed = Box::new(import.clone()); let boxed = Box::new(import.clone());
// Use None for the justification importer since justifications always come with blocks // Use None for the justification importer since justifications always come with blocks

View File

@@ -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_runtime::traits::Block as BlockTrait;
use sp_inherents::CreateInherentDataProviders; use sp_inherents::CreateInherentDataProviders;
@@ -14,11 +14,12 @@ use substrate_prometheus_endpoint::Registry;
use serai_runtime::{self, opaque::Block, RuntimeApi}; use serai_runtime::{self, opaque::Block, RuntimeApi};
mod types; mod types;
use types::{TendermintClientMinimal, TendermintAuthor}; use types::{TendermintClientMinimal, TendermintValidator};
mod validators; mod validators;
mod tendermint; mod tendermint;
pub use tendermint::TendermintAuthority;
mod block_import; mod block_import;
mod verifier; mod verifier;
@@ -54,7 +55,7 @@ pub trait Announce<B: BlockTrait>: Send + Sync + Clone + 'static {
fn announce(&self, hash: B::Hash); fn announce(&self, hash: B::Hash);
} }
struct Cidp; pub struct Cidp;
#[async_trait::async_trait] #[async_trait::async_trait]
impl CreateInherentDataProviders<Block, ()> for Cidp { impl CreateInherentDataProviders<Block, ()> for Cidp {
type InherentDataProviders = (sp_timestamp::InherentDataProvider,); type InherentDataProviders = (sp_timestamp::InherentDataProvider,);
@@ -67,15 +68,15 @@ impl CreateInherentDataProviders<Block, ()> for Cidp {
} }
} }
struct TendermintAuthorFirm<A: Announce<Block>>(PhantomData<A>); pub struct TendermintValidatorFirm<A: Announce<Block>>(PhantomData<A>);
impl<A: Announce<Block>> TendermintClientMinimal for TendermintAuthorFirm<A> { impl<A: Announce<Block>> TendermintClientMinimal for TendermintValidatorFirm<A> {
type Block = Block; type Block = Block;
type Backend = sc_client_db::Backend<Block>; type Backend = sc_client_db::Backend<Block>;
type Api = <FullClient as ProvideRuntimeApi<Block>>::Api; type Api = <FullClient as ProvideRuntimeApi<Block>>::Api;
type Client = FullClient; type Client = FullClient;
} }
impl<A: Announce<Block>> TendermintAuthor for TendermintAuthorFirm<A> { impl<A: Announce<Block>> TendermintValidator for TendermintValidatorFirm<A> {
type CIDP = Cidp; type CIDP = Cidp;
type Environment = sc_basic_authorship::ProposerFactory< type Environment = sc_basic_authorship::ProposerFactory<
FullPool<Block, FullClient>, FullPool<Block, FullClient>,
@@ -93,8 +94,11 @@ pub fn import_queue<A: Announce<Block>>(
announce: A, announce: A,
pool: Arc<FullPool<Block, FullClient>>, pool: Arc<FullPool<Block, FullClient>>,
registry: Option<&Registry>, registry: Option<&Registry>,
) -> (impl Future<Output = ()>, TendermintImportQueue<Block, TransactionFor<FullClient, Block>>) { ) -> (
import_queue::import_queue::<TendermintAuthorFirm<A>>( TendermintAuthority<TendermintValidatorFirm<A>>,
TendermintImportQueue<Block, TransactionFor<FullClient, Block>>,
) {
import_queue::import_queue::<TendermintValidatorFirm<A>>(
client.clone(), client.clone(),
announce, announce,
Arc::new(Cidp), Arc::new(Cidp),

View File

@@ -1,7 +1,7 @@
use std::{ use std::{
marker::PhantomData, marker::PhantomData,
sync::{Arc, RwLock}, sync::{Arc, RwLock},
time::Duration, time::{UNIX_EPOCH, SystemTime, Duration},
}; };
use async_trait::async_trait; 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_consensus::{ForkChoiceStrategy, BlockImportParams, import_queue::IncomingBlock};
use sc_service::ImportQueue; use sc_service::ImportQueue;
use sc_client_api::Finalizer; use sc_client_api::{BlockBackend, Finalizer};
use tendermint_machine::{ use tendermint_machine::{
ext::{BlockError, Commit, Network}, ext::{BlockError, BlockNumber, Commit, Network},
SignedMessage, TendermintHandle, SignedMessage, TendermintMachine, TendermintHandle,
}; };
use crate::{ use crate::{
CONSENSUS_ID, CONSENSUS_ID,
types::TendermintAuthor, types::TendermintValidator,
validators::TendermintValidators, validators::TendermintValidators,
import_queue::{ImportFuture, TendermintImportQueue}, import_queue::{ImportFuture, TendermintImportQueue},
Announce, Announce,
}; };
pub(crate) struct TendermintImport<T: TendermintAuthor> { pub(crate) struct TendermintImport<T: TendermintValidator> {
_ta: PhantomData<T>, _ta: PhantomData<T>,
validators: Arc<TendermintValidators<T>>, validators: Arc<TendermintValidators<T>>,
@@ -55,7 +55,46 @@ pub(crate) struct TendermintImport<T: TendermintAuthor> {
Arc<AsyncRwLock<Option<TendermintImportQueue<T::Block, T::BackendTransaction>>>>, Arc<AsyncRwLock<Option<TendermintImportQueue<T::Block, T::BackendTransaction>>>>,
} }
impl<T: TendermintAuthor> Clone for TendermintImport<T> { pub struct TendermintAuthority<T: TendermintValidator>(pub(crate) TendermintImport<T>);
impl<T: TendermintValidator> TendermintAuthority<T> {
pub async fn validate(mut self) {
let info = self.0.client.info();
// Header::Number: TryInto<u64> doesn't implement Debug and can't be unwrapped
let start_number = match TryInto::<u64>::try_into(info.best_number) {
Ok(best) => BlockNumber(best + 1),
Err(_) => panic!("BlockNumber exceeded u64"),
};
let start_time = Commit::<TendermintValidators<T>>::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<T: TendermintValidator> Clone for TendermintImport<T> {
fn clone(&self) -> Self { fn clone(&self) -> Self {
TendermintImport { TendermintImport {
_ta: PhantomData, _ta: PhantomData,
@@ -75,7 +114,7 @@ impl<T: TendermintAuthor> Clone for TendermintImport<T> {
} }
} }
impl<T: TendermintAuthor> TendermintImport<T> { impl<T: TendermintValidator> TendermintImport<T> {
pub(crate) fn new( pub(crate) fn new(
client: Arc<T::Client>, client: Arc<T::Client>,
announce: T::Announce, announce: T::Announce,
@@ -254,7 +293,7 @@ impl<T: TendermintAuthor> TendermintImport<T> {
} }
#[async_trait] #[async_trait]
impl<T: TendermintAuthor> Network for TendermintImport<T> { impl<T: TendermintValidator> Network for TendermintImport<T> {
type ValidatorId = u16; type ValidatorId = u16;
type SignatureScheme = TendermintValidators<T>; type SignatureScheme = TendermintValidators<T>;
type Weights = TendermintValidators<T>; type Weights = TendermintValidators<T>;

View File

@@ -67,7 +67,7 @@ where
} }
/// Trait consolidating additional generics required by sc_tendermint for authoring. /// Trait consolidating additional generics required by sc_tendermint for authoring.
pub trait TendermintAuthor: TendermintClient { pub trait TendermintValidator: TendermintClient {
type CIDP: CreateInherentDataProviders<Self::Block, ()> + 'static; type CIDP: CreateInherentDataProviders<Self::Block, ()> + 'static;
type Environment: Send + Sync + Environment<Self::Block> + 'static; type Environment: Send + Sync + Environment<Self::Block> + 'static;

View File

@@ -5,10 +5,10 @@ use async_trait::async_trait;
use sp_consensus::{Error, CacheKeyId}; use sp_consensus::{Error, CacheKeyId};
use sc_consensus::{BlockImportParams, BlockImport, Verifier}; use sc_consensus::{BlockImportParams, BlockImport, Verifier};
use crate::{types::TendermintAuthor, tendermint::TendermintImport}; use crate::{types::TendermintValidator, tendermint::TendermintImport};
#[async_trait] #[async_trait]
impl<T: TendermintAuthor> Verifier<T::Block> for TendermintImport<T> impl<T: TendermintValidator> Verifier<T::Block> for TendermintImport<T>
where where
Arc<T::Client>: BlockImport<T::Block, Transaction = T::BackendTransaction>, Arc<T::Client>: BlockImport<T::Block, Transaction = T::BackendTransaction>,
<Arc<T::Client> as BlockImport<T::Block>>::Error: Into<Error>, <Arc<T::Client> as BlockImport<T::Block>>::Error: Into<Error>,