diff --git a/Cargo.lock b/Cargo.lock index 5844d3ec..f87293fb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7387,6 +7387,7 @@ name = "serai-consensus" version = "0.1.0" dependencies = [ "async-trait", + "log", "sc-basic-authorship", "sc-client-api", "sc-consensus", diff --git a/substrate/consensus/Cargo.toml b/substrate/consensus/Cargo.toml index f1bfb984..756ac11d 100644 --- a/substrate/consensus/Cargo.toml +++ b/substrate/consensus/Cargo.toml @@ -15,6 +15,8 @@ rustdoc-args = ["--cfg", "docsrs"] [dependencies] async-trait = "0.1" +log = "0.4" + tokio = "1" sp-core = { git = "https://github.com/serai-dex/substrate" } diff --git a/substrate/consensus/src/import_queue.rs b/substrate/consensus/src/import_queue.rs index e887b82d..c00c2e31 100644 --- a/substrate/consensus/src/import_queue.rs +++ b/substrate/consensus/src/import_queue.rs @@ -14,24 +14,27 @@ use std::{ marker::PhantomData, sync::{Arc, RwLock}, + time::Duration, collections::HashMap, }; use async_trait::async_trait; +use log::warn; + use tokio::sync::RwLock as AsyncRwLock; use sp_core::{Encode, Decode}; use sp_application_crypto::sr25519::Signature; -use sp_inherents::CreateInherentDataProviders; +use sp_inherents::{InherentData, InherentDataProvider, CreateInherentDataProviders}; use sp_runtime::{ traits::{Header, Block}, - Justification, + Digest, Justification, }; use sp_blockchain::HeaderBackend; use sp_api::{BlockId, TransactionFor, ProvideRuntimeApi}; -use sp_consensus::{Error, CacheKeyId}; +use sp_consensus::{Error, CacheKeyId, Proposer, Environment}; #[rustfmt::skip] // rustfmt doesn't know how to handle this line use sc_consensus::{ ForkChoiceStrategy, @@ -63,6 +66,7 @@ struct TendermintImport< C: Send + Sync + HeaderBackend + Finalizer + ProvideRuntimeApi + 'static, I: Send + Sync + BlockImport> + 'static, CIDP: CreateInherentDataProviders + 'static, + E: Send + Sync + Environment + 'static, > { _block: PhantomData, _backend: PhantomData, @@ -72,6 +76,8 @@ struct TendermintImport< client: Arc, inner: Arc>, providers: Arc, + + env: Arc>, } impl< @@ -80,7 +86,8 @@ impl< C: Send + Sync + HeaderBackend + Finalizer + ProvideRuntimeApi + 'static, I: Send + Sync + BlockImport> + 'static, CIDP: CreateInherentDataProviders + 'static, - > Clone for TendermintImport + E: Send + Sync + Environment + 'static, + > Clone for TendermintImport { fn clone(&self) -> Self { TendermintImport { @@ -92,6 +99,8 @@ impl< client: self.client.clone(), inner: self.inner.clone(), providers: self.providers.clone(), + + env: self.env.clone(), } } } @@ -102,7 +111,8 @@ impl< C: Send + Sync + HeaderBackend + Finalizer + ProvideRuntimeApi + 'static, I: Send + Sync + BlockImport> + 'static, CIDP: CreateInherentDataProviders + 'static, - > TendermintImport + E: Send + Sync + Environment + 'static, + > TendermintImport { async fn check_inherents( &self, @@ -240,7 +250,8 @@ impl< C: Send + Sync + HeaderBackend + Finalizer + ProvideRuntimeApi + 'static, I: Send + Sync + BlockImport> + 'static, CIDP: CreateInherentDataProviders + 'static, - > BlockImport for TendermintImport + E: Send + Sync + Environment + 'static, + > BlockImport for TendermintImport where I::Error: Into, { @@ -281,7 +292,8 @@ impl< C: Send + Sync + HeaderBackend + Finalizer + ProvideRuntimeApi + 'static, I: Send + Sync + BlockImport> + 'static, CIDP: CreateInherentDataProviders + 'static, - > JustificationImport for TendermintImport + E: Send + Sync + Environment + 'static, + > JustificationImport for TendermintImport { type Error = Error; @@ -306,7 +318,8 @@ impl< C: Send + Sync + HeaderBackend + Finalizer + ProvideRuntimeApi + 'static, I: Send + Sync + BlockImport> + 'static, CIDP: CreateInherentDataProviders + 'static, - > Verifier for TendermintImport + E: Send + Sync + Environment + 'static, + > Verifier for TendermintImport { async fn verify( &mut self, @@ -324,7 +337,8 @@ impl< C: Send + Sync + HeaderBackend + Finalizer + ProvideRuntimeApi + 'static, I: Send + Sync + BlockImport> + 'static, CIDP: CreateInherentDataProviders + 'static, - > Network for TendermintImport + E: Send + Sync + Environment + 'static, + > Network for TendermintImport { type ValidatorId = u16; type SignatureScheme = TendermintSigner; @@ -356,10 +370,38 @@ impl< // Ok(()) } - fn add_block(&mut self, block: B, commit: Commit) -> B { - self.import_justification_actual(block.hash(), (CONSENSUS_ID, commit.encode())).unwrap(); - // Next block proposal - todo!() + async fn add_block(&mut self, block: B, commit: Commit) -> B { + let hash = block.hash(); + self.import_justification_actual(hash, (CONSENSUS_ID, commit.encode())).unwrap(); + + let inherent_data = match self.providers.create_inherent_data_providers(hash, ()).await { + Ok(providers) => match providers.create_inherent_data() { + Ok(data) => Some(data), + Err(err) => { + warn!(target: "tendermint", "Failed to create inherent data: {}", err); + None + } + }, + Err(err) => { + warn!(target: "tendermint", "Failed to create inherent data providers: {}", err); + None + } + } + .unwrap_or_else(InherentData::new); + + let proposer = self + .env + .write() + .await + .init(block.header()) + .await + .expect("Failed to create a proposer for the new block"); + // TODO: Production time, size limit + let proposal = proposer + .propose(inherent_data, Digest::default(), Duration::from_secs(1), None) + .await + .expect("Failed to crate a new block proposal"); + proposal.block } } @@ -371,10 +413,12 @@ pub fn import_queue< C: Send + Sync + HeaderBackend + Finalizer + ProvideRuntimeApi + 'static, I: Send + Sync + BlockImport> + 'static, CIDP: CreateInherentDataProviders + 'static, + E: Send + Sync + Environment + 'static, >( client: Arc, inner: I, providers: Arc, + env: E, spawner: &impl sp_core::traits::SpawnEssentialNamed, registry: Option<&Registry>, ) -> TendermintImportQueue> @@ -390,6 +434,8 @@ where client, inner: Arc::new(AsyncRwLock::new(inner)), providers, + + env: Arc::new(AsyncRwLock::new(env)), }; let boxed = Box::new(import.clone()); diff --git a/substrate/consensus/src/lib.rs b/substrate/consensus/src/lib.rs index 7dc9e730..a912d29e 100644 --- a/substrate/consensus/src/lib.rs +++ b/substrate/consensus/src/lib.rs @@ -4,6 +4,7 @@ use sp_api::TransactionFor; use sp_consensus::Error; use sc_executor::{NativeVersion, NativeExecutionDispatch, NativeElseWasmExecutor}; +use sc_transaction_pool::FullPool; use sc_service::{TaskManager, TFullClient}; use substrate_prometheus_endpoint::Registry; @@ -40,12 +41,20 @@ pub type FullClient = TFullClient, + pool: Arc>, registry: Option<&Registry>, ) -> Result>, Error> { Ok(import_queue::import_queue( client.clone(), - client, + client.clone(), Arc::new(|_, _| async { Ok(sp_timestamp::InherentDataProvider::from_system_time()) }), + sc_basic_authorship::ProposerFactory::new( + task_manager.spawn_handle(), + client, + pool, + registry, + None, + ), &task_manager.spawn_essential_handle(), registry, )) @@ -56,7 +65,7 @@ pub fn authority( task_manager: &TaskManager, client: Arc, network: Arc::Hash>>, - pool: Arc>, + pool: Arc>, registry: Option<&Registry>, ) { todo!() diff --git a/substrate/node/src/chain_spec.rs b/substrate/node/src/chain_spec.rs index 88fc0949..fb21bec7 100644 --- a/substrate/node/src/chain_spec.rs +++ b/substrate/node/src/chain_spec.rs @@ -1,9 +1,8 @@ use sc_service::ChainType; -use sp_runtime::traits::Verify; use sp_core::{Pair as PairTrait, sr25519::Pair}; -use serai_runtime::{WASM_BINARY, AccountId, Signature, GenesisConfig, SystemConfig, BalancesConfig}; +use serai_runtime::{WASM_BINARY, AccountId, GenesisConfig, SystemConfig, BalancesConfig}; pub type ChainSpec = sc_service::GenericChainSpec; diff --git a/substrate/node/src/service.rs b/substrate/node/src/service.rs index fe8671fc..b97ce890 100644 --- a/substrate/node/src/service.rs +++ b/substrate/node/src/service.rs @@ -63,8 +63,12 @@ pub fn new_partial(config: &Configuration) -> Result) - -> Self::Block; + async fn add_block( + &mut self, + block: Self::Block, + commit: Commit, + ) -> Self::Block; } diff --git a/substrate/tendermint/src/lib.rs b/substrate/tendermint/src/lib.rs index 5b65b3b9..b420f5dc 100644 --- a/substrate/tendermint/src/lib.rs +++ b/substrate/tendermint/src/lib.rs @@ -318,7 +318,7 @@ impl TendermintMachine { }; debug_assert!(machine.network.read().await.verify_commit(block.id(), &commit)); - let proposal = machine.network.write().await.add_block(block, commit); + let proposal = machine.network.write().await.add_block(block, commit).await; machine.reset(proposal).await; } Err(TendermintError::Malicious(validator)) => { diff --git a/substrate/tendermint/tests/ext.rs b/substrate/tendermint/tests/ext.rs index 6f489f7a..6122c939 100644 --- a/substrate/tendermint/tests/ext.rs +++ b/substrate/tendermint/tests/ext.rs @@ -113,7 +113,11 @@ impl Network for TestNetwork { block.valid } - fn add_block(&mut self, block: TestBlock, commit: Commit) -> TestBlock { + async fn add_block( + &mut self, + block: TestBlock, + commit: Commit, + ) -> TestBlock { dbg!("Adding ", &block); assert!(block.valid.is_ok()); assert!(self.verify_commit(block.id(), &commit));