mirror of
https://github.com/serai-dex/serai.git
synced 2025-02-03 11:46:31 +00:00
Implement proper checking of inherents
This commit is contained in:
parent
19154cf8e1
commit
aa0a4cf106
8 changed files with 89 additions and 41 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -7328,6 +7328,7 @@ dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"futures",
|
"futures",
|
||||||
"log",
|
"log",
|
||||||
|
"sc-block-builder",
|
||||||
"sc-client-api",
|
"sc-client-api",
|
||||||
"sc-consensus",
|
"sc-consensus",
|
||||||
"sc-executor",
|
"sc-executor",
|
||||||
|
@ -8884,6 +8885,7 @@ dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"parity-scale-codec",
|
"parity-scale-codec",
|
||||||
"sp-runtime",
|
"sp-runtime",
|
||||||
|
"thiserror",
|
||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,7 @@ sc-network = { git = "https://github.com/serai-dex/substrate" }
|
||||||
sc-network-gossip = { git = "https://github.com/serai-dex/substrate" }
|
sc-network-gossip = { git = "https://github.com/serai-dex/substrate" }
|
||||||
sc-service = { git = "https://github.com/serai-dex/substrate" }
|
sc-service = { git = "https://github.com/serai-dex/substrate" }
|
||||||
sc-client-api = { git = "https://github.com/serai-dex/substrate" }
|
sc-client-api = { git = "https://github.com/serai-dex/substrate" }
|
||||||
|
sc-block-builder = { git = "https://github.com/serai-dex/substrate" }
|
||||||
sc-consensus = { git = "https://github.com/serai-dex/substrate" }
|
sc-consensus = { git = "https://github.com/serai-dex/substrate" }
|
||||||
|
|
||||||
substrate-prometheus-endpoint = { git = "https://github.com/serai-dex/substrate" }
|
substrate-prometheus-endpoint = { git = "https://github.com/serai-dex/substrate" }
|
||||||
|
|
|
@ -7,27 +7,39 @@ use std::{
|
||||||
|
|
||||||
use sp_runtime::traits::{Header, Block};
|
use sp_runtime::traits::{Header, Block};
|
||||||
|
|
||||||
|
use sp_consensus::Error;
|
||||||
use sc_consensus::{BlockImportStatus, BlockImportError, Link};
|
use sc_consensus::{BlockImportStatus, BlockImportError, Link};
|
||||||
|
|
||||||
use sc_service::ImportQueue;
|
use sc_service::ImportQueue;
|
||||||
|
|
||||||
|
use tendermint_machine::ext::BlockError;
|
||||||
|
|
||||||
use crate::TendermintImportQueue;
|
use crate::TendermintImportQueue;
|
||||||
|
|
||||||
// Custom helpers for ImportQueue in order to obtain the result of a block's importing
|
// Custom helpers for ImportQueue in order to obtain the result of a block's importing
|
||||||
struct ValidateLink<B: Block>(Option<(B::Hash, bool)>);
|
struct ValidateLink<B: Block>(Option<(B::Hash, Result<(), BlockError>)>);
|
||||||
impl<B: Block> Link<B> for ValidateLink<B> {
|
impl<B: Block> Link<B> for ValidateLink<B> {
|
||||||
fn blocks_processed(
|
fn blocks_processed(
|
||||||
&mut self,
|
&mut self,
|
||||||
imported: usize,
|
imported: usize,
|
||||||
count: usize,
|
count: usize,
|
||||||
results: Vec<(
|
mut results: Vec<(
|
||||||
Result<BlockImportStatus<<B::Header as Header>::Number>, BlockImportError>,
|
Result<BlockImportStatus<<B::Header as Header>::Number>, BlockImportError>,
|
||||||
B::Hash,
|
B::Hash,
|
||||||
)>,
|
)>,
|
||||||
) {
|
) {
|
||||||
assert_eq!(imported, 1);
|
assert_eq!(imported, 1);
|
||||||
assert_eq!(count, 1);
|
assert_eq!(count, 1);
|
||||||
self.0 = Some((results[0].1, results[0].0.is_ok()));
|
self.0 = Some((
|
||||||
|
results[0].1,
|
||||||
|
match results.swap_remove(0).0 {
|
||||||
|
Ok(_) => Ok(()),
|
||||||
|
Err(BlockImportError::Other(Error::Other(err))) => Err(
|
||||||
|
err.downcast::<BlockError>().map(|boxed| *boxed.as_ref()).unwrap_or(BlockError::Fatal),
|
||||||
|
),
|
||||||
|
_ => Err(BlockError::Fatal),
|
||||||
|
},
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,7 +57,7 @@ impl<'a, B: Block, T: Send> ImportFuture<'a, B, T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, B: Block, T: Send> Future for ImportFuture<'a, B, T> {
|
impl<'a, B: Block, T: Send> Future for ImportFuture<'a, B, T> {
|
||||||
type Output = bool;
|
type Output = Result<(), BlockError>;
|
||||||
|
|
||||||
fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> {
|
fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
let mut link = ValidateLink(None);
|
let mut link = ValidateLink(None);
|
||||||
|
|
|
@ -10,7 +10,6 @@ use log::warn;
|
||||||
use tokio::task::yield_now;
|
use tokio::task::yield_now;
|
||||||
|
|
||||||
use sp_core::{Encode, Decode};
|
use sp_core::{Encode, Decode};
|
||||||
use sp_inherents::{InherentData, InherentDataProvider, CreateInherentDataProviders};
|
|
||||||
use sp_runtime::{
|
use sp_runtime::{
|
||||||
traits::{Header, Block},
|
traits::{Header, Block},
|
||||||
Digest,
|
Digest,
|
||||||
|
@ -105,29 +104,7 @@ impl<T: TendermintValidator> TendermintAuthority<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn get_proposal(&mut self, header: &<T::Block as Block>::Header) -> T::Block {
|
pub(crate) async fn get_proposal(&mut self, header: &<T::Block as Block>::Header) -> T::Block {
|
||||||
let inherent_data = match self
|
let parent = *header.parent_hash();
|
||||||
.import
|
|
||||||
.providers
|
|
||||||
.read()
|
|
||||||
.await
|
|
||||||
.as_ref()
|
|
||||||
.unwrap()
|
|
||||||
.create_inherent_data_providers(header.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
|
let proposer = self
|
||||||
.active
|
.active
|
||||||
|
@ -137,9 +114,15 @@ impl<T: TendermintValidator> TendermintAuthority<T> {
|
||||||
.init(header)
|
.init(header)
|
||||||
.await
|
.await
|
||||||
.expect("Failed to create a proposer for the new block");
|
.expect("Failed to create a proposer for the new block");
|
||||||
// TODO: Production time, size limit
|
|
||||||
proposer
|
proposer
|
||||||
.propose(inherent_data, Digest::default(), Duration::from_secs(1), None)
|
.propose(
|
||||||
|
self.import.inherent_data(parent).await,
|
||||||
|
Digest::default(),
|
||||||
|
// TODO: Production time, size limit
|
||||||
|
Duration::from_secs(1),
|
||||||
|
None,
|
||||||
|
)
|
||||||
.await
|
.await
|
||||||
.expect("Failed to crate a new block proposal")
|
.expect("Failed to crate a new block proposal")
|
||||||
.block
|
.block
|
||||||
|
@ -316,9 +299,7 @@ impl<T: TendermintValidator> Network for TendermintAuthority<T> {
|
||||||
}],
|
}],
|
||||||
);
|
);
|
||||||
|
|
||||||
if !ImportFuture::new(hash, queue_write.as_mut().unwrap()).await {
|
ImportFuture::new(hash, queue_write.as_mut().unwrap()).await?;
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sanity checks that a child block can have less work than its parent
|
// Sanity checks that a child block can have less work than its parent
|
||||||
{
|
{
|
||||||
|
|
|
@ -7,6 +7,7 @@ use sp_api::{StateBackend, StateBackendFor, TransactionFor, ApiExt, ProvideRunti
|
||||||
use sp_consensus::{Error, Environment};
|
use sp_consensus::{Error, Environment};
|
||||||
|
|
||||||
use sc_client_api::{BlockBackend, Backend, Finalizer};
|
use sc_client_api::{BlockBackend, Backend, Finalizer};
|
||||||
|
use sc_block_builder::BlockBuilderApi;
|
||||||
use sc_consensus::{BlockImport, BasicQueue};
|
use sc_consensus::{BlockImport, BasicQueue};
|
||||||
use sc_network::NetworkBlock;
|
use sc_network::NetworkBlock;
|
||||||
use sc_network_gossip::Network;
|
use sc_network_gossip::Network;
|
||||||
|
@ -43,7 +44,9 @@ pub trait TendermintClient: Send + Sync + 'static {
|
||||||
Transaction = Self::BackendTransaction,
|
Transaction = Self::BackendTransaction,
|
||||||
>;
|
>;
|
||||||
// Client::Api
|
// Client::Api
|
||||||
type Api: ApiExt<Self::Block, StateBackend = Self::StateBackend> + TendermintApi<Self::Block>;
|
type Api: ApiExt<Self::Block, StateBackend = Self::StateBackend>
|
||||||
|
+ BlockBuilderApi<Self::Block>
|
||||||
|
+ TendermintApi<Self::Block>;
|
||||||
type Client: Send
|
type Client: Send
|
||||||
+ Sync
|
+ Sync
|
||||||
+ HeaderBackend<Self::Block>
|
+ HeaderBackend<Self::Block>
|
||||||
|
@ -60,7 +63,7 @@ pub trait TendermintClientMinimal: Send + Sync + 'static {
|
||||||
|
|
||||||
type Block: Block;
|
type Block: Block;
|
||||||
type Backend: Backend<Self::Block> + 'static;
|
type Backend: Backend<Self::Block> + 'static;
|
||||||
type Api: ApiExt<Self::Block> + TendermintApi<Self::Block>;
|
type Api: ApiExt<Self::Block> + BlockBuilderApi<Self::Block> + TendermintApi<Self::Block>;
|
||||||
type Client: Send
|
type Client: Send
|
||||||
+ Sync
|
+ Sync
|
||||||
+ HeaderBackend<Self::Block>
|
+ HeaderBackend<Self::Block>
|
||||||
|
@ -73,7 +76,8 @@ pub trait TendermintClientMinimal: Send + Sync + 'static {
|
||||||
|
|
||||||
impl<T: TendermintClientMinimal> TendermintClient for T
|
impl<T: TendermintClientMinimal> TendermintClient for T
|
||||||
where
|
where
|
||||||
<T::Client as ProvideRuntimeApi<T::Block>>::Api: TendermintApi<T::Block>,
|
<T::Client as ProvideRuntimeApi<T::Block>>::Api:
|
||||||
|
BlockBuilderApi<T::Block> + TendermintApi<T::Block>,
|
||||||
TransactionFor<T::Client, T::Block>: Send + Sync + 'static,
|
TransactionFor<T::Client, T::Block>: Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
const BLOCK_TIME_IN_SECONDS: u32 = T::BLOCK_TIME_IN_SECONDS;
|
const BLOCK_TIME_IN_SECONDS: u32 = T::BLOCK_TIME_IN_SECONDS;
|
||||||
|
|
|
@ -3,6 +3,8 @@ use std::{
|
||||||
sync::{Arc, RwLock},
|
sync::{Arc, RwLock},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use log::warn;
|
||||||
|
|
||||||
use tokio::sync::RwLock as AsyncRwLock;
|
use tokio::sync::RwLock as AsyncRwLock;
|
||||||
|
|
||||||
use sp_core::Decode;
|
use sp_core::Decode;
|
||||||
|
@ -10,12 +12,16 @@ use sp_runtime::{
|
||||||
traits::{Header, Block},
|
traits::{Header, Block},
|
||||||
Justification,
|
Justification,
|
||||||
};
|
};
|
||||||
|
use sp_inherents::{InherentData, InherentDataProvider, CreateInherentDataProviders};
|
||||||
use sp_blockchain::HeaderBackend;
|
use sp_blockchain::HeaderBackend;
|
||||||
|
use sp_api::{BlockId, ProvideRuntimeApi};
|
||||||
|
|
||||||
use sp_consensus::Error;
|
use sp_consensus::Error;
|
||||||
use sc_consensus::{ForkChoiceStrategy, BlockImportParams};
|
use sc_consensus::{ForkChoiceStrategy, BlockImportParams};
|
||||||
|
|
||||||
use tendermint_machine::ext::{Commit, Network};
|
use sc_block_builder::BlockBuilderApi;
|
||||||
|
|
||||||
|
use tendermint_machine::ext::{BlockError, Commit, Network};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
CONSENSUS_ID, TendermintValidator, validators::TendermintValidators, TendermintImportQueue,
|
CONSENSUS_ID, TendermintValidator, validators::TendermintValidators, TendermintImportQueue,
|
||||||
|
@ -67,9 +73,46 @@ impl<T: TendermintValidator> TendermintImport<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) async fn inherent_data(&self, parent: <T::Block as Block>::Hash) -> InherentData {
|
||||||
|
match self
|
||||||
|
.providers
|
||||||
|
.read()
|
||||||
|
.await
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.create_inherent_data_providers(parent, ())
|
||||||
|
.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)
|
||||||
|
}
|
||||||
|
|
||||||
async fn check_inherents(&self, block: T::Block) -> Result<(), Error> {
|
async fn check_inherents(&self, block: T::Block) -> Result<(), Error> {
|
||||||
// TODO
|
let inherent_data = self.inherent_data(*block.header().parent_hash()).await;
|
||||||
Ok(())
|
let err = self
|
||||||
|
.client
|
||||||
|
.runtime_api()
|
||||||
|
.check_inherents(&BlockId::Hash(self.client.info().finalized_hash), block, inherent_data)
|
||||||
|
.map_err(|_| Error::Other(BlockError::Fatal.into()))?;
|
||||||
|
|
||||||
|
if err.ok() {
|
||||||
|
Ok(())
|
||||||
|
} else if err.fatal_error() {
|
||||||
|
Err(Error::Other(BlockError::Fatal.into()))
|
||||||
|
} else {
|
||||||
|
Err(Error::Other(BlockError::Temporal.into()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure this is part of a sequential import
|
// Ensure this is part of a sequential import
|
||||||
|
|
|
@ -8,9 +8,11 @@ authors = ["Luke Parker <lukeparker5132@gmail.com>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
async-trait = "0.1"
|
||||||
|
thiserror = "1"
|
||||||
|
|
||||||
parity-scale-codec = { version = "3.2", features = ["derive"] }
|
parity-scale-codec = { version = "3.2", features = ["derive"] }
|
||||||
|
|
||||||
async-trait = "0.1"
|
|
||||||
tokio = { version = "1", features = ["macros", "sync", "time", "rt"] }
|
tokio = { version = "1", features = ["macros", "sync", "time", "rt"] }
|
||||||
|
|
||||||
sp-runtime = { git = "https://github.com/serai-dex/substrate", optional = true }
|
sp-runtime = { git = "https://github.com/serai-dex/substrate", optional = true }
|
||||||
|
|
|
@ -2,6 +2,7 @@ use core::{hash::Hash, fmt::Debug};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
use parity_scale_codec::{Encode, Decode};
|
use parity_scale_codec::{Encode, Decode};
|
||||||
|
|
||||||
|
@ -97,12 +98,14 @@ pub trait Weights: Send + Sync {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Simplified error enum representing a block's validity.
|
/// Simplified error enum representing a block's validity.
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Encode, Decode)]
|
#[derive(Clone, Copy, PartialEq, Eq, Debug, Error, Encode, Decode)]
|
||||||
pub enum BlockError {
|
pub enum BlockError {
|
||||||
/// Malformed block which is wholly invalid.
|
/// Malformed block which is wholly invalid.
|
||||||
|
#[error("invalid block")]
|
||||||
Fatal,
|
Fatal,
|
||||||
/// Valid block by syntax, with semantics which may or may not be valid yet are locally
|
/// Valid block by syntax, with semantics which may or may not be valid yet are locally
|
||||||
/// considered invalid. If a block fails to validate with this, a slash will not be triggered.
|
/// considered invalid. If a block fails to validate with this, a slash will not be triggered.
|
||||||
|
#[error("invalid block under local view")]
|
||||||
Temporal,
|
Temporal,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue