Files
serai/coordinator/tributary-sdk/tendermint/src/round.rs
Luke Parker 3c664ff05f Re-arrange coordinator/
coordinator/tributary was tributary-chain. This crate has been renamed
tributary-sdk and moved to coordinator/tributary-sdk.

coordinator/src/tributary was our instantion of a Tributary, the Transaction
type and scan task. This has been moved to coordinator/tributary.

The main reason for this was due to coordinator/main.rs becoming untidy. There
is now a collection of clean, independent APIs present in the codebase.
coordinator/main.rs is to compose them. Sometimes, these compositions are a bit
silly (reading from a channel just to forward the message to a distinct
channel). That's more than fine as the code is still readable and the value
from the cleanliness of the APIs composed far exceeds the nits from having
these odd compositions.

This breaks down a bit as we now define a global database, and have some APIs
interact with multiple other APIs.

coordinator/src/tributary was a self-contained, clean API. The recently added
task present in coordinator/tributary/mod.rs, which bound it to the rest of the
Coordinator, wasn't.

Now, coordinator/src is solely the API compositions, and all self-contained
APIs are their own crates.
2025-01-11 04:14:21 -05:00

94 lines
2.5 KiB
Rust

use std::{
marker::PhantomData,
time::{Duration, Instant},
collections::HashMap,
};
use futures_util::{FutureExt, future};
use patchable_async_sleep::sleep;
use crate::{
time::CanonicalInstant,
Step,
ext::{RoundNumber, Network},
};
pub struct RoundData<N: Network> {
_network: PhantomData<N>,
pub number: RoundNumber,
pub start_time: CanonicalInstant,
pub step: Step,
pub timeouts: HashMap<Step, Instant>,
}
impl<N: Network> RoundData<N> {
pub fn new(number: RoundNumber, start_time: CanonicalInstant) -> Self {
RoundData {
_network: PhantomData,
number,
start_time,
step: Step::Propose,
timeouts: HashMap::new(),
}
}
fn timeout(&self, step: Step) -> CanonicalInstant {
let adjusted_block = N::BLOCK_PROCESSING_TIME * (self.number.0 + 1);
let adjusted_latency = N::LATENCY_TIME * (self.number.0 + 1);
let offset = Duration::from_millis(
(match step {
Step::Propose => adjusted_block + adjusted_latency,
Step::Prevote => adjusted_block + (2 * adjusted_latency),
Step::Precommit => adjusted_block + (3 * adjusted_latency),
})
.into(),
);
self.start_time + offset
}
pub fn end_time(&self) -> CanonicalInstant {
self.timeout(Step::Precommit)
}
pub(crate) fn set_timeout(&mut self, step: Step) {
let timeout = self.timeout(step).instant();
self.timeouts.entry(step).or_insert(timeout);
}
// Poll all set timeouts, returning the Step whose timeout has just expired
pub(crate) async fn timeout_future(&self) -> Step {
/*
let now = Instant::now();
log::trace!(
target: "tendermint",
"getting timeout_future, from step {:?}, off timeouts: {:?}",
self.step,
self.timeouts.iter().map(|(k, v)| (k, v.duration_since(now))).collect::<HashMap<_, _>>()
);
*/
let timeout_future = |step| {
let timeout = self.timeouts.get(&step).copied();
(async move {
if let Some(timeout) = timeout {
sleep(timeout.saturating_duration_since(Instant::now())).await;
} else {
future::pending::<()>().await;
}
step
})
.fuse()
};
let propose_timeout = timeout_future(Step::Propose);
let prevote_timeout = timeout_future(Step::Prevote);
let precommit_timeout = timeout_future(Step::Precommit);
futures_util::pin_mut!(propose_timeout, prevote_timeout, precommit_timeout);
futures_util::select_biased! {
step = propose_timeout => step,
step = prevote_timeout => step,
step = precommit_timeout => step,
}
}
}