use derive_where::derive_where;
use crate::input::Input;
use crate::state_machine::Info;
use crate::transition::Transition;
#[cfg(feature = "debug")]
use crate::traces::*;
use malachitebft_core_types::{Context, Height, Round};
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct RoundValue<Value> {
pub value: Value,
pub round: Round,
}
impl<Value> RoundValue<Value> {
pub fn new(value: Value, round: Round) -> Self {
Self { value, round }
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Step {
Unstarted,
Propose,
Prevote,
Precommit,
Commit,
}
#[derive_where(Clone, Debug, PartialEq, Eq)]
pub struct State<Ctx>
where
Ctx: Context,
{
pub height: Ctx::Height,
pub round: Round,
pub step: Step,
pub locked: Option<RoundValue<Ctx::Value>>,
pub valid: Option<RoundValue<Ctx::Value>>,
pub decision: Option<RoundValue<Ctx::Value>>,
#[cfg(feature = "debug")]
#[derive_where(skip)]
pub traces: alloc::vec::Vec<Trace<Ctx>>,
}
impl<Ctx> State<Ctx>
where
Ctx: Context,
{
pub fn new(height: Ctx::Height, round: Round) -> Self {
Self {
height,
round,
step: Step::Unstarted,
locked: None,
valid: None,
decision: None,
#[cfg(feature = "debug")]
traces: alloc::vec::Vec::default(),
}
}
pub fn with_round(self, round: Round) -> Self {
Self { round, ..self }
}
pub fn with_step(self, step: Step) -> Self {
Self { step, ..self }
}
pub fn set_locked(self, value: Ctx::Value) -> Self {
Self {
locked: Some(RoundValue::new(value, self.round)),
..self
}
}
pub fn set_valid(self, value: Ctx::Value) -> Self {
Self {
valid: Some(RoundValue::new(value, self.round)),
..self
}
}
pub fn set_decision(self, proposal_round: Round, value: Ctx::Value) -> Self {
Self {
decision: Some(RoundValue::new(value, proposal_round)),
..self
}
}
pub fn apply(self, ctx: &Ctx, data: &Info<Ctx>, input: Input<Ctx>) -> Transition<Ctx> {
crate::state_machine::apply(ctx, self, data, input)
}
#[cfg(feature = "debug")]
pub fn add_trace(&mut self, line: Line) {
self.traces.push(Trace::new(self.height, self.round, line));
}
#[cfg(feature = "debug")]
pub fn get_traces(&self) -> &[Trace<Ctx>] {
&self.traces
}
}
impl<Ctx> Default for State<Ctx>
where
Ctx: Context,
{
fn default() -> Self {
Self::new(Ctx::Height::ZERO, Round::Nil)
}
}