mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-08 12:19:24 +00:00
Separate the block processing time from the latency
This commit is contained in:
@@ -18,7 +18,7 @@ pub(crate) use sc_tendermint::{
|
|||||||
TendermintClientMinimal, TendermintValidator, TendermintImport, TendermintAuthority,
|
TendermintClientMinimal, TendermintValidator, TendermintImport, TendermintAuthority,
|
||||||
TendermintSelectChain, import_queue,
|
TendermintSelectChain, import_queue,
|
||||||
};
|
};
|
||||||
use serai_runtime::{self, MILLISECS_PER_BLOCK, opaque::Block, RuntimeApi};
|
use serai_runtime::{self, TARGET_BLOCK_TIME, opaque::Block, RuntimeApi};
|
||||||
|
|
||||||
type FullBackend = sc_service::TFullBackend<Block>;
|
type FullBackend = sc_service::TFullBackend<Block>;
|
||||||
pub type FullClient = TFullClient<Block, RuntimeApi, NativeElseWasmExecutor<ExecutorDispatch>>;
|
pub type FullClient = TFullClient<Block, RuntimeApi, NativeElseWasmExecutor<ExecutorDispatch>>;
|
||||||
@@ -63,7 +63,10 @@ impl CreateInherentDataProviders<Block, ()> for Cidp {
|
|||||||
|
|
||||||
pub struct TendermintValidatorFirm;
|
pub struct TendermintValidatorFirm;
|
||||||
impl TendermintClientMinimal for TendermintValidatorFirm {
|
impl TendermintClientMinimal for TendermintValidatorFirm {
|
||||||
const BLOCK_TIME_IN_SECONDS: u32 = { (MILLISECS_PER_BLOCK / 1000) as u32 };
|
// 3 seconds
|
||||||
|
const BLOCK_PROCESSING_TIME_IN_SECONDS: u32 = { (TARGET_BLOCK_TIME / 2 / 1000) as u32 };
|
||||||
|
// 1 second
|
||||||
|
const LATENCY_TIME_IN_SECONDS: u32 = { (TARGET_BLOCK_TIME / 2 / 3 / 1000) as u32 };
|
||||||
|
|
||||||
type Block = Block;
|
type Block = Block;
|
||||||
type Backend = sc_client_db::Backend<Block>;
|
type Backend = sc_client_db::Backend<Block>;
|
||||||
@@ -86,6 +89,8 @@ impl TendermintValidator for TendermintValidatorFirm {
|
|||||||
pub fn new_partial(
|
pub fn new_partial(
|
||||||
config: &Configuration,
|
config: &Configuration,
|
||||||
) -> Result<(TendermintImport<TendermintValidatorFirm>, PartialComponents), ServiceError> {
|
) -> Result<(TendermintImport<TendermintValidatorFirm>, PartialComponents), ServiceError> {
|
||||||
|
debug_assert_eq!(TARGET_BLOCK_TIME, 6000);
|
||||||
|
|
||||||
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()));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,11 +79,10 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
|
|||||||
state_version: 1,
|
state_version: 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const MILLISECS_PER_BLOCK: u64 = 6000;
|
pub const TARGET_BLOCK_TIME: u64 = 6000;
|
||||||
pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK;
|
|
||||||
|
|
||||||
/// Measured in blocks.
|
/// Measured in blocks.
|
||||||
pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber);
|
pub const MINUTES: BlockNumber = 60_000 / (TARGET_BLOCK_TIME as BlockNumber);
|
||||||
pub const HOURS: BlockNumber = MINUTES * 60;
|
pub const HOURS: BlockNumber = MINUTES * 60;
|
||||||
pub const DAYS: BlockNumber = HOURS * 24;
|
pub const DAYS: BlockNumber = HOURS * 24;
|
||||||
|
|
||||||
@@ -164,7 +163,7 @@ impl pallet_randomness_collective_flip::Config for Runtime {}
|
|||||||
impl pallet_timestamp::Config for Runtime {
|
impl pallet_timestamp::Config for Runtime {
|
||||||
type Moment = u64;
|
type Moment = u64;
|
||||||
type OnTimestampSet = ();
|
type OnTimestampSet = ();
|
||||||
type MinimumPeriod = ConstU64<{ SLOT_DURATION / 2 }>;
|
type MinimumPeriod = ConstU64<{ TARGET_BLOCK_TIME / 2 }>;
|
||||||
type WeightInfo = ();
|
type WeightInfo = ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -130,8 +130,9 @@ impl<T: TendermintValidator> TendermintAuthority<T> {
|
|||||||
.propose(
|
.propose(
|
||||||
self.import.inherent_data(parent).await,
|
self.import.inherent_data(parent).await,
|
||||||
Digest::default(),
|
Digest::default(),
|
||||||
// TODO: Production time, size limit
|
// Assumes a block cannot take longer to download than it'll take to process
|
||||||
Duration::from_secs(1),
|
Duration::from_secs((T::BLOCK_PROCESSING_TIME_IN_SECONDS / 2).into()),
|
||||||
|
// TODO: Size limit
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
@@ -253,7 +254,8 @@ impl<T: TendermintValidator> Network for TendermintAuthority<T> {
|
|||||||
type Weights = TendermintValidators<T>;
|
type Weights = TendermintValidators<T>;
|
||||||
type Block = T::Block;
|
type Block = T::Block;
|
||||||
|
|
||||||
const BLOCK_TIME: u32 = T::BLOCK_TIME_IN_SECONDS;
|
const BLOCK_PROCESSING_TIME: u32 = T::BLOCK_PROCESSING_TIME_IN_SECONDS;
|
||||||
|
const LATENCY_TIME: u32 = T::LATENCY_TIME_IN_SECONDS;
|
||||||
|
|
||||||
fn signer(&self) -> TendermintSigner<T> {
|
fn signer(&self) -> TendermintSigner<T> {
|
||||||
self.active.as_ref().unwrap().signer.clone()
|
self.active.as_ref().unwrap().signer.clone()
|
||||||
|
|||||||
@@ -53,7 +53,8 @@ pub fn set_config(protocol: ProtocolName) -> NonDefaultSetConfig {
|
|||||||
|
|
||||||
/// Trait consolidating all generics required by sc_tendermint for processing.
|
/// Trait consolidating all generics required by sc_tendermint for processing.
|
||||||
pub trait TendermintClient: Send + Sync + 'static {
|
pub trait TendermintClient: Send + Sync + 'static {
|
||||||
const BLOCK_TIME_IN_SECONDS: u32;
|
const BLOCK_PROCESSING_TIME_IN_SECONDS: u32;
|
||||||
|
const LATENCY_TIME_IN_SECONDS: u32;
|
||||||
|
|
||||||
type Block: Block;
|
type Block: Block;
|
||||||
type Backend: Backend<Self::Block> + 'static;
|
type Backend: Backend<Self::Block> + 'static;
|
||||||
@@ -81,7 +82,8 @@ pub trait TendermintClient: Send + Sync + 'static {
|
|||||||
|
|
||||||
/// Trait implementable on firm types to automatically provide a full TendermintClient impl.
|
/// Trait implementable on firm types to automatically provide a full TendermintClient impl.
|
||||||
pub trait TendermintClientMinimal: Send + Sync + 'static {
|
pub trait TendermintClientMinimal: Send + Sync + 'static {
|
||||||
const BLOCK_TIME_IN_SECONDS: u32;
|
const BLOCK_PROCESSING_TIME_IN_SECONDS: u32;
|
||||||
|
const LATENCY_TIME_IN_SECONDS: u32;
|
||||||
|
|
||||||
type Block: Block;
|
type Block: Block;
|
||||||
type Backend: Backend<Self::Block> + 'static;
|
type Backend: Backend<Self::Block> + 'static;
|
||||||
@@ -102,7 +104,8 @@ where
|
|||||||
BlockBuilderApi<T::Block> + TendermintApi<T::Block>,
|
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_PROCESSING_TIME_IN_SECONDS: u32 = T::BLOCK_PROCESSING_TIME_IN_SECONDS;
|
||||||
|
const LATENCY_TIME_IN_SECONDS: u32 = T::LATENCY_TIME_IN_SECONDS;
|
||||||
|
|
||||||
type Block = T::Block;
|
type Block = T::Block;
|
||||||
type Backend = T::Backend;
|
type Backend = T::Backend;
|
||||||
|
|||||||
@@ -207,8 +207,16 @@ pub trait Network: Send + Sync {
|
|||||||
/// Type used for ordered blocks of information.
|
/// Type used for ordered blocks of information.
|
||||||
type Block: Block;
|
type Block: Block;
|
||||||
|
|
||||||
// Block time in seconds
|
/// Maximum block processing time in seconds. This should include both the actual processing time
|
||||||
const BLOCK_TIME: u32;
|
/// and the time to download the block.
|
||||||
|
const BLOCK_PROCESSING_TIME: u32;
|
||||||
|
/// Network latency time in seconds.
|
||||||
|
const LATENCY_TIME: u32;
|
||||||
|
|
||||||
|
/// The block time is defined as the processing time plus three times the latency.
|
||||||
|
fn block_time() -> u32 {
|
||||||
|
Self::BLOCK_PROCESSING_TIME + (3 * Self::LATENCY_TIME)
|
||||||
|
}
|
||||||
|
|
||||||
/// Return a handle on the signer in use, usable for the entire lifetime of the machine.
|
/// Return a handle on the signer in use, usable for the entire lifetime of the machine.
|
||||||
fn signer(&self) -> <Self::SignatureScheme as SignatureScheme>::Signer;
|
fn signer(&self) -> <Self::SignatureScheme as SignatureScheme>::Signer;
|
||||||
|
|||||||
@@ -155,23 +155,22 @@ impl<N: Network + 'static> TendermintMachine<N> {
|
|||||||
fn canonical_end_time(&self, round: Round) -> u64 {
|
fn canonical_end_time(&self, round: Round) -> u64 {
|
||||||
let mut time = self.canonical_start_time;
|
let mut time = self.canonical_start_time;
|
||||||
for r in 0 .. u64::from(round.0 + 1) {
|
for r in 0 .. u64::from(round.0 + 1) {
|
||||||
time += (r + 1) * u64::from(N::BLOCK_TIME);
|
time += (r + 1) * u64::from(N::block_time());
|
||||||
}
|
}
|
||||||
time
|
time
|
||||||
}
|
}
|
||||||
|
|
||||||
fn timeout(&self, step: Step) -> Instant {
|
fn timeout(&self, step: Step) -> Instant {
|
||||||
let mut round_time = Duration::from_secs(N::BLOCK_TIME.into());
|
let adjusted_block = N::BLOCK_PROCESSING_TIME * (self.round.0 + 1);
|
||||||
round_time *= self.round.0 + 1;
|
let adjusted_latency = N::LATENCY_TIME * (self.round.0 + 1);
|
||||||
// TODO: Non-uniform timeouts. Proposal has to validate the block which will take much longer
|
let offset = Duration::from_secs(
|
||||||
// than any other step
|
(match step {
|
||||||
let step_time = round_time / 3;
|
Step::Propose => adjusted_block + adjusted_latency,
|
||||||
|
Step::Prevote => adjusted_block + (2 * adjusted_latency),
|
||||||
let offset = match step {
|
Step::Precommit => adjusted_block + (3 * adjusted_latency),
|
||||||
Step::Propose => step_time,
|
})
|
||||||
Step::Prevote => step_time * 2,
|
.into(),
|
||||||
Step::Precommit => step_time * 3,
|
);
|
||||||
};
|
|
||||||
self.start_time + offset
|
self.start_time + offset
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -301,7 +300,7 @@ impl<N: Network + 'static> TendermintMachine<N> {
|
|||||||
// Using the genesis time in place will cause this block to be created immediately
|
// Using the genesis time in place will cause this block to be created immediately
|
||||||
// after it, without the standard amount of separation (so their times will be
|
// after it, without the standard amount of separation (so their times will be
|
||||||
// equivalent or minimally offset)
|
// equivalent or minimally offset)
|
||||||
// For callers wishing to avoid this, they should pass (0, GENESIS + BLOCK_TIME)
|
// For callers wishing to avoid this, they should pass (0, GENESIS + N::block_time())
|
||||||
start_time: last_time,
|
start_time: last_time,
|
||||||
personal_proposal: proposal,
|
personal_proposal: proposal,
|
||||||
|
|
||||||
|
|||||||
@@ -103,7 +103,8 @@ impl Network for TestNetwork {
|
|||||||
type Weights = TestWeights;
|
type Weights = TestWeights;
|
||||||
type Block = TestBlock;
|
type Block = TestBlock;
|
||||||
|
|
||||||
const BLOCK_TIME: u32 = 1;
|
const BLOCK_PROCESSING_TIME: u32 = 2;
|
||||||
|
const LATENCY_TIME: u32 = 1;
|
||||||
|
|
||||||
fn signer(&self) -> TestSigner {
|
fn signer(&self) -> TestSigner {
|
||||||
TestSigner(self.0)
|
TestSigner(self.0)
|
||||||
@@ -168,7 +169,5 @@ impl TestNetwork {
|
|||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test() {
|
async fn test() {
|
||||||
TestNetwork::new(4).await;
|
TestNetwork::new(4).await;
|
||||||
for _ in 0 .. 10 {
|
sleep(Duration::from_secs(30)).await;
|
||||||
sleep(Duration::from_secs(1)).await;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user