mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-09 12:49:23 +00:00
Implement block proposal logic
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -7387,6 +7387,7 @@ name = "serai-consensus"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
|
"log",
|
||||||
"sc-basic-authorship",
|
"sc-basic-authorship",
|
||||||
"sc-client-api",
|
"sc-client-api",
|
||||||
"sc-consensus",
|
"sc-consensus",
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ rustdoc-args = ["--cfg", "docsrs"]
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
async-trait = "0.1"
|
async-trait = "0.1"
|
||||||
|
|
||||||
|
log = "0.4"
|
||||||
|
|
||||||
tokio = "1"
|
tokio = "1"
|
||||||
|
|
||||||
sp-core = { git = "https://github.com/serai-dex/substrate" }
|
sp-core = { git = "https://github.com/serai-dex/substrate" }
|
||||||
|
|||||||
@@ -14,24 +14,27 @@
|
|||||||
use std::{
|
use std::{
|
||||||
marker::PhantomData,
|
marker::PhantomData,
|
||||||
sync::{Arc, RwLock},
|
sync::{Arc, RwLock},
|
||||||
|
time::Duration,
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
};
|
};
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
|
||||||
|
use log::warn;
|
||||||
|
|
||||||
use tokio::sync::RwLock as AsyncRwLock;
|
use tokio::sync::RwLock as AsyncRwLock;
|
||||||
|
|
||||||
use sp_core::{Encode, Decode};
|
use sp_core::{Encode, Decode};
|
||||||
use sp_application_crypto::sr25519::Signature;
|
use sp_application_crypto::sr25519::Signature;
|
||||||
use sp_inherents::CreateInherentDataProviders;
|
use sp_inherents::{InherentData, InherentDataProvider, CreateInherentDataProviders};
|
||||||
use sp_runtime::{
|
use sp_runtime::{
|
||||||
traits::{Header, Block},
|
traits::{Header, Block},
|
||||||
Justification,
|
Digest, Justification,
|
||||||
};
|
};
|
||||||
use sp_blockchain::HeaderBackend;
|
use sp_blockchain::HeaderBackend;
|
||||||
use sp_api::{BlockId, TransactionFor, ProvideRuntimeApi};
|
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
|
#[rustfmt::skip] // rustfmt doesn't know how to handle this line
|
||||||
use sc_consensus::{
|
use sc_consensus::{
|
||||||
ForkChoiceStrategy,
|
ForkChoiceStrategy,
|
||||||
@@ -63,6 +66,7 @@ struct TendermintImport<
|
|||||||
C: Send + Sync + HeaderBackend<B> + Finalizer<B, Be> + ProvideRuntimeApi<B> + 'static,
|
C: Send + Sync + HeaderBackend<B> + Finalizer<B, Be> + ProvideRuntimeApi<B> + 'static,
|
||||||
I: Send + Sync + BlockImport<B, Transaction = TransactionFor<C, B>> + 'static,
|
I: Send + Sync + BlockImport<B, Transaction = TransactionFor<C, B>> + 'static,
|
||||||
CIDP: CreateInherentDataProviders<B, ()> + 'static,
|
CIDP: CreateInherentDataProviders<B, ()> + 'static,
|
||||||
|
E: Send + Sync + Environment<B> + 'static,
|
||||||
> {
|
> {
|
||||||
_block: PhantomData<B>,
|
_block: PhantomData<B>,
|
||||||
_backend: PhantomData<Be>,
|
_backend: PhantomData<Be>,
|
||||||
@@ -72,6 +76,8 @@ struct TendermintImport<
|
|||||||
client: Arc<C>,
|
client: Arc<C>,
|
||||||
inner: Arc<AsyncRwLock<I>>,
|
inner: Arc<AsyncRwLock<I>>,
|
||||||
providers: Arc<CIDP>,
|
providers: Arc<CIDP>,
|
||||||
|
|
||||||
|
env: Arc<AsyncRwLock<E>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<
|
impl<
|
||||||
@@ -80,7 +86,8 @@ impl<
|
|||||||
C: Send + Sync + HeaderBackend<B> + Finalizer<B, Be> + ProvideRuntimeApi<B> + 'static,
|
C: Send + Sync + HeaderBackend<B> + Finalizer<B, Be> + ProvideRuntimeApi<B> + 'static,
|
||||||
I: Send + Sync + BlockImport<B, Transaction = TransactionFor<C, B>> + 'static,
|
I: Send + Sync + BlockImport<B, Transaction = TransactionFor<C, B>> + 'static,
|
||||||
CIDP: CreateInherentDataProviders<B, ()> + 'static,
|
CIDP: CreateInherentDataProviders<B, ()> + 'static,
|
||||||
> Clone for TendermintImport<B, Be, C, I, CIDP>
|
E: Send + Sync + Environment<B> + 'static,
|
||||||
|
> Clone for TendermintImport<B, Be, C, I, CIDP, E>
|
||||||
{
|
{
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
TendermintImport {
|
TendermintImport {
|
||||||
@@ -92,6 +99,8 @@ impl<
|
|||||||
client: self.client.clone(),
|
client: self.client.clone(),
|
||||||
inner: self.inner.clone(),
|
inner: self.inner.clone(),
|
||||||
providers: self.providers.clone(),
|
providers: self.providers.clone(),
|
||||||
|
|
||||||
|
env: self.env.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -102,7 +111,8 @@ impl<
|
|||||||
C: Send + Sync + HeaderBackend<B> + Finalizer<B, Be> + ProvideRuntimeApi<B> + 'static,
|
C: Send + Sync + HeaderBackend<B> + Finalizer<B, Be> + ProvideRuntimeApi<B> + 'static,
|
||||||
I: Send + Sync + BlockImport<B, Transaction = TransactionFor<C, B>> + 'static,
|
I: Send + Sync + BlockImport<B, Transaction = TransactionFor<C, B>> + 'static,
|
||||||
CIDP: CreateInherentDataProviders<B, ()> + 'static,
|
CIDP: CreateInherentDataProviders<B, ()> + 'static,
|
||||||
> TendermintImport<B, Be, C, I, CIDP>
|
E: Send + Sync + Environment<B> + 'static,
|
||||||
|
> TendermintImport<B, Be, C, I, CIDP, E>
|
||||||
{
|
{
|
||||||
async fn check_inherents(
|
async fn check_inherents(
|
||||||
&self,
|
&self,
|
||||||
@@ -240,7 +250,8 @@ impl<
|
|||||||
C: Send + Sync + HeaderBackend<B> + Finalizer<B, Be> + ProvideRuntimeApi<B> + 'static,
|
C: Send + Sync + HeaderBackend<B> + Finalizer<B, Be> + ProvideRuntimeApi<B> + 'static,
|
||||||
I: Send + Sync + BlockImport<B, Transaction = TransactionFor<C, B>> + 'static,
|
I: Send + Sync + BlockImport<B, Transaction = TransactionFor<C, B>> + 'static,
|
||||||
CIDP: CreateInherentDataProviders<B, ()> + 'static,
|
CIDP: CreateInherentDataProviders<B, ()> + 'static,
|
||||||
> BlockImport<B> for TendermintImport<B, Be, C, I, CIDP>
|
E: Send + Sync + Environment<B> + 'static,
|
||||||
|
> BlockImport<B> for TendermintImport<B, Be, C, I, CIDP, E>
|
||||||
where
|
where
|
||||||
I::Error: Into<Error>,
|
I::Error: Into<Error>,
|
||||||
{
|
{
|
||||||
@@ -281,7 +292,8 @@ impl<
|
|||||||
C: Send + Sync + HeaderBackend<B> + Finalizer<B, Be> + ProvideRuntimeApi<B> + 'static,
|
C: Send + Sync + HeaderBackend<B> + Finalizer<B, Be> + ProvideRuntimeApi<B> + 'static,
|
||||||
I: Send + Sync + BlockImport<B, Transaction = TransactionFor<C, B>> + 'static,
|
I: Send + Sync + BlockImport<B, Transaction = TransactionFor<C, B>> + 'static,
|
||||||
CIDP: CreateInherentDataProviders<B, ()> + 'static,
|
CIDP: CreateInherentDataProviders<B, ()> + 'static,
|
||||||
> JustificationImport<B> for TendermintImport<B, Be, C, I, CIDP>
|
E: Send + Sync + Environment<B> + 'static,
|
||||||
|
> JustificationImport<B> for TendermintImport<B, Be, C, I, CIDP, E>
|
||||||
{
|
{
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
@@ -306,7 +318,8 @@ impl<
|
|||||||
C: Send + Sync + HeaderBackend<B> + Finalizer<B, Be> + ProvideRuntimeApi<B> + 'static,
|
C: Send + Sync + HeaderBackend<B> + Finalizer<B, Be> + ProvideRuntimeApi<B> + 'static,
|
||||||
I: Send + Sync + BlockImport<B, Transaction = TransactionFor<C, B>> + 'static,
|
I: Send + Sync + BlockImport<B, Transaction = TransactionFor<C, B>> + 'static,
|
||||||
CIDP: CreateInherentDataProviders<B, ()> + 'static,
|
CIDP: CreateInherentDataProviders<B, ()> + 'static,
|
||||||
> Verifier<B> for TendermintImport<B, Be, C, I, CIDP>
|
E: Send + Sync + Environment<B> + 'static,
|
||||||
|
> Verifier<B> for TendermintImport<B, Be, C, I, CIDP, E>
|
||||||
{
|
{
|
||||||
async fn verify(
|
async fn verify(
|
||||||
&mut self,
|
&mut self,
|
||||||
@@ -324,7 +337,8 @@ impl<
|
|||||||
C: Send + Sync + HeaderBackend<B> + Finalizer<B, Be> + ProvideRuntimeApi<B> + 'static,
|
C: Send + Sync + HeaderBackend<B> + Finalizer<B, Be> + ProvideRuntimeApi<B> + 'static,
|
||||||
I: Send + Sync + BlockImport<B, Transaction = TransactionFor<C, B>> + 'static,
|
I: Send + Sync + BlockImport<B, Transaction = TransactionFor<C, B>> + 'static,
|
||||||
CIDP: CreateInherentDataProviders<B, ()> + 'static,
|
CIDP: CreateInherentDataProviders<B, ()> + 'static,
|
||||||
> Network for TendermintImport<B, Be, C, I, CIDP>
|
E: Send + Sync + Environment<B> + 'static,
|
||||||
|
> Network for TendermintImport<B, Be, C, I, CIDP, E>
|
||||||
{
|
{
|
||||||
type ValidatorId = u16;
|
type ValidatorId = u16;
|
||||||
type SignatureScheme = TendermintSigner;
|
type SignatureScheme = TendermintSigner;
|
||||||
@@ -356,10 +370,38 @@ impl<
|
|||||||
// Ok(())
|
// Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_block(&mut self, block: B, commit: Commit<TendermintSigner>) -> B {
|
async fn add_block(&mut self, block: B, commit: Commit<TendermintSigner>) -> B {
|
||||||
self.import_justification_actual(block.hash(), (CONSENSUS_ID, commit.encode())).unwrap();
|
let hash = block.hash();
|
||||||
// Next block proposal
|
self.import_justification_actual(hash, (CONSENSUS_ID, commit.encode())).unwrap();
|
||||||
todo!()
|
|
||||||
|
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<B> + Finalizer<B, Be> + ProvideRuntimeApi<B> + 'static,
|
C: Send + Sync + HeaderBackend<B> + Finalizer<B, Be> + ProvideRuntimeApi<B> + 'static,
|
||||||
I: Send + Sync + BlockImport<B, Transaction = TransactionFor<C, B>> + 'static,
|
I: Send + Sync + BlockImport<B, Transaction = TransactionFor<C, B>> + 'static,
|
||||||
CIDP: CreateInherentDataProviders<B, ()> + 'static,
|
CIDP: CreateInherentDataProviders<B, ()> + 'static,
|
||||||
|
E: Send + Sync + Environment<B> + 'static,
|
||||||
>(
|
>(
|
||||||
client: Arc<C>,
|
client: Arc<C>,
|
||||||
inner: I,
|
inner: I,
|
||||||
providers: Arc<CIDP>,
|
providers: Arc<CIDP>,
|
||||||
|
env: E,
|
||||||
spawner: &impl sp_core::traits::SpawnEssentialNamed,
|
spawner: &impl sp_core::traits::SpawnEssentialNamed,
|
||||||
registry: Option<&Registry>,
|
registry: Option<&Registry>,
|
||||||
) -> TendermintImportQueue<B, TransactionFor<C, B>>
|
) -> TendermintImportQueue<B, TransactionFor<C, B>>
|
||||||
@@ -390,6 +434,8 @@ where
|
|||||||
client,
|
client,
|
||||||
inner: Arc::new(AsyncRwLock::new(inner)),
|
inner: Arc::new(AsyncRwLock::new(inner)),
|
||||||
providers,
|
providers,
|
||||||
|
|
||||||
|
env: Arc::new(AsyncRwLock::new(env)),
|
||||||
};
|
};
|
||||||
let boxed = Box::new(import.clone());
|
let boxed = Box::new(import.clone());
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ use sp_api::TransactionFor;
|
|||||||
use sp_consensus::Error;
|
use sp_consensus::Error;
|
||||||
|
|
||||||
use sc_executor::{NativeVersion, NativeExecutionDispatch, NativeElseWasmExecutor};
|
use sc_executor::{NativeVersion, NativeExecutionDispatch, NativeElseWasmExecutor};
|
||||||
|
use sc_transaction_pool::FullPool;
|
||||||
use sc_service::{TaskManager, TFullClient};
|
use sc_service::{TaskManager, TFullClient};
|
||||||
|
|
||||||
use substrate_prometheus_endpoint::Registry;
|
use substrate_prometheus_endpoint::Registry;
|
||||||
@@ -40,12 +41,20 @@ pub type FullClient = TFullClient<Block, RuntimeApi, NativeElseWasmExecutor<Exec
|
|||||||
pub fn import_queue(
|
pub fn import_queue(
|
||||||
task_manager: &TaskManager,
|
task_manager: &TaskManager,
|
||||||
client: Arc<FullClient>,
|
client: Arc<FullClient>,
|
||||||
|
pool: Arc<FullPool<Block, FullClient>>,
|
||||||
registry: Option<&Registry>,
|
registry: Option<&Registry>,
|
||||||
) -> Result<TendermintImportQueue<Block, TransactionFor<FullClient, Block>>, Error> {
|
) -> Result<TendermintImportQueue<Block, TransactionFor<FullClient, Block>>, Error> {
|
||||||
Ok(import_queue::import_queue(
|
Ok(import_queue::import_queue(
|
||||||
client.clone(),
|
client.clone(),
|
||||||
client,
|
client.clone(),
|
||||||
Arc::new(|_, _| async { Ok(sp_timestamp::InherentDataProvider::from_system_time()) }),
|
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(),
|
&task_manager.spawn_essential_handle(),
|
||||||
registry,
|
registry,
|
||||||
))
|
))
|
||||||
@@ -56,7 +65,7 @@ pub fn authority(
|
|||||||
task_manager: &TaskManager,
|
task_manager: &TaskManager,
|
||||||
client: Arc<FullClient>,
|
client: Arc<FullClient>,
|
||||||
network: Arc<sc_network::NetworkService<Block, <Block as sp_runtime::traits::Block>::Hash>>,
|
network: Arc<sc_network::NetworkService<Block, <Block as sp_runtime::traits::Block>::Hash>>,
|
||||||
pool: Arc<sc_transaction_pool::FullPool<Block, FullClient>>,
|
pool: Arc<FullPool<Block, FullClient>>,
|
||||||
registry: Option<&Registry>,
|
registry: Option<&Registry>,
|
||||||
) {
|
) {
|
||||||
todo!()
|
todo!()
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
use sc_service::ChainType;
|
use sc_service::ChainType;
|
||||||
|
|
||||||
use sp_runtime::traits::Verify;
|
|
||||||
use sp_core::{Pair as PairTrait, sr25519::Pair};
|
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<GenesisConfig>;
|
pub type ChainSpec = sc_service::GenericChainSpec<GenesisConfig>;
|
||||||
|
|
||||||
|
|||||||
@@ -63,8 +63,12 @@ pub fn new_partial(config: &Configuration) -> Result<PartialComponents, ServiceE
|
|||||||
client.clone(),
|
client.clone(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let import_queue =
|
let import_queue = serai_consensus::import_queue(
|
||||||
serai_consensus::import_queue(&task_manager, client.clone(), config.prometheus_registry())?;
|
&task_manager,
|
||||||
|
client.clone(),
|
||||||
|
transaction_pool.clone(),
|
||||||
|
config.prometheus_registry(),
|
||||||
|
)?;
|
||||||
|
|
||||||
let select_chain = serai_consensus::TendermintSelectChain::new(backend.clone());
|
let select_chain = serai_consensus::TendermintSelectChain::new(backend.clone());
|
||||||
|
|
||||||
|
|||||||
@@ -186,6 +186,9 @@ pub trait Network: Send + Sync {
|
|||||||
/// consider it valid and created a commit for it. This deviates from the paper which will have a
|
/// consider it valid and created a commit for it. This deviates from the paper which will have a
|
||||||
/// local node refuse to decide on a block it considers invalid. This library acknowledges the
|
/// local node refuse to decide on a block it considers invalid. This library acknowledges the
|
||||||
/// network did decide on it, leaving handling of it to the network, and outside of this scope.
|
/// network did decide on it, leaving handling of it to the network, and outside of this scope.
|
||||||
fn add_block(&mut self, block: Self::Block, commit: Commit<Self::SignatureScheme>)
|
async fn add_block(
|
||||||
-> Self::Block;
|
&mut self,
|
||||||
|
block: Self::Block,
|
||||||
|
commit: Commit<Self::SignatureScheme>,
|
||||||
|
) -> Self::Block;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -318,7 +318,7 @@ impl<N: Network + 'static> TendermintMachine<N> {
|
|||||||
};
|
};
|
||||||
debug_assert!(machine.network.read().await.verify_commit(block.id(), &commit));
|
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;
|
machine.reset(proposal).await;
|
||||||
}
|
}
|
||||||
Err(TendermintError::Malicious(validator)) => {
|
Err(TendermintError::Malicious(validator)) => {
|
||||||
|
|||||||
@@ -113,7 +113,11 @@ impl Network for TestNetwork {
|
|||||||
block.valid
|
block.valid
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_block(&mut self, block: TestBlock, commit: Commit<TestSignatureScheme>) -> TestBlock {
|
async fn add_block(
|
||||||
|
&mut self,
|
||||||
|
block: TestBlock,
|
||||||
|
commit: Commit<TestSignatureScheme>,
|
||||||
|
) -> TestBlock {
|
||||||
dbg!("Adding ", &block);
|
dbg!("Adding ", &block);
|
||||||
assert!(block.valid.is_ok());
|
assert!(block.valid.is_ok());
|
||||||
assert!(self.verify_commit(block.id(), &commit));
|
assert!(self.verify_commit(block.id(), &commit));
|
||||||
|
|||||||
Reference in New Issue
Block a user