From 3b08633445b569ff409b5c94c74671d9b6fb0097 Mon Sep 17 00:00:00 2001 From: Luke Parker Date: Fri, 21 Oct 2022 02:18:51 -0400 Subject: [PATCH] BlockImport, JustificationImport, Verifier, and import_queue function --- substrate/consensus/src/import_queue.rs | 167 ++++++++++++++++++++++++ 1 file changed, 167 insertions(+) diff --git a/substrate/consensus/src/import_queue.rs b/substrate/consensus/src/import_queue.rs index d88d1f91..cdf6ced3 100644 --- a/substrate/consensus/src/import_queue.rs +++ b/substrate/consensus/src/import_queue.rs @@ -37,6 +37,7 @@ use sc_consensus::{ ForkChoiceStrategy, BlockCheckParams, BlockImportParams, + Verifier, ImportResult, BlockImport, JustificationImport, @@ -218,3 +219,169 @@ impl< Ok(()) } } + +#[async_trait] +impl< + B: Block, + Be: Backend + 'static, + C: Send + Sync + HeaderBackend + Finalizer + ProvideRuntimeApi + 'static, + I: Send + Sync + BlockImport> + 'static, + CIDP: CreateInherentDataProviders + 'static, + > BlockImport for TendermintImport +where + I::Error: Into, +{ + type Error = Error; + type Transaction = TransactionFor; + + // TODO: Is there a DoS where you send a block without justifications, causing it to error, + // yet adding it to the blacklist in the process preventing further syncing? + async fn check_block( + &mut self, + mut block: BlockCheckParams, + ) -> Result { + self.verify_order(block.parent_hash, block.number)?; + + // Does not verify origin here as origin only applies to unfinalized blocks + // We don't have context on if this block has justifications or not + + block.allow_missing_state = false; + block.allow_missing_parent = false; + + self.inner.write().await.check_block(block).await.map_err(Into::into) + } + + async fn import_block( + &mut self, + mut block: BlockImportParams>, + new_cache: HashMap>, + ) -> Result { + self.check(&mut block).await?; + self.inner.write().await.import_block(block, new_cache).await.map_err(Into::into) + } +} + +#[async_trait] +impl< + B: Block, + Be: Backend + 'static, + C: Send + Sync + HeaderBackend + Finalizer + ProvideRuntimeApi + 'static, + I: Send + Sync + BlockImport> + 'static, + CIDP: CreateInherentDataProviders + 'static, + > JustificationImport for TendermintImport +{ + type Error = Error; + + async fn on_start(&mut self) -> Vec<(B::Hash, ::Number)> { + vec![] + } + + async fn import_justification( + &mut self, + hash: B::Hash, + _: ::Number, + justification: Justification, + ) -> Result<(), Error> { + self.verify_justification(hash, &justification)?; + self + .client + .finalize_block(BlockId::Hash(hash), Some(justification), true) + .map_err(|_| Error::InvalidJustification) + } +} + +#[async_trait] +impl< + B: Block, + Be: Backend + 'static, + C: Send + Sync + HeaderBackend + Finalizer + ProvideRuntimeApi + 'static, + I: Send + Sync + BlockImport> + 'static, + CIDP: CreateInherentDataProviders + 'static, + > Verifier for TendermintImport +{ + async fn verify( + &mut self, + mut block: BlockImportParams, + ) -> Result<(BlockImportParams, Option)>>), String> { + self.check(&mut block).await.map_err(|e| format!("{}", e))?; + Ok((block, None)) + } +} + +#[async_trait] +impl< + B: Block, + Be: Backend + 'static, + C: Send + Sync + HeaderBackend + Finalizer + ProvideRuntimeApi + 'static, + I: Send + Sync + BlockImport> + 'static, + CIDP: CreateInherentDataProviders + 'static, + > Network for TendermintImport +{ + type ValidatorId = u16; + type SignatureScheme = TendermintSigner; + type Weights = TendermintWeights; + type Block = B; + + const BLOCK_TIME: u32 = { (serai_runtime::MILLISECS_PER_BLOCK / 1000) as u32 }; + + fn signature_scheme(&self) -> Arc { + todo!() + } + + fn weights(&self) -> Arc { + Arc::new(TendermintWeights) + } + + async fn broadcast(&mut self, msg: SignedMessage) { + todo!() + } + + async fn slash(&mut self, validator: u16) { + todo!() + } + + fn validate(&mut self, block: &B) -> Result<(), BlockError> { + todo!() + // self.check_block().map_err(|_| BlockError::Temporal)?; + // self.import_block().map_err(|_| BlockError::Temporal)?; + // Ok(()) + } + + fn add_block(&mut self, block: B, commit: Commit) -> B { + todo!() + } +} + +pub type TendermintImportQueue = BasicQueue; + +pub fn import_queue< + B: Block, + Be: Backend + 'static, + C: Send + Sync + HeaderBackend + Finalizer + ProvideRuntimeApi + 'static, + I: Send + Sync + BlockImport> + 'static, + CIDP: CreateInherentDataProviders + 'static, +>( + client: Arc, + inner: I, + providers: Arc, + spawner: &impl sp_core::traits::SpawnEssentialNamed, + registry: Option<&Registry>, +) -> TendermintImportQueue> +where + I::Error: Into, +{ + let import = TendermintImport { + _block: PhantomData, + _backend: PhantomData, + + importing_block: Arc::new(RwLock::new(None)), + + client, + inner: Arc::new(AsyncRwLock::new(inner)), + providers, + }; + let boxed = Box::new(import.clone()); + + // TODO: Fully read BasicQueue in otder to understand it + BasicQueue::new(import, boxed.clone(), Some(boxed), spawner, registry) +}