tendermint/consensus/
state.rspub use core::{cmp::Ordering, fmt};
use serde::{Deserialize, Serialize};
pub use crate::block;
use crate::prelude::*;
pub const NIL_PLACEHOLDER: &str = "<nil>";
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
pub struct State {
pub height: block::Height,
pub round: block::Round,
pub step: i8,
#[serde(with = "tendermint_proto::serializers::optional")]
pub block_id: Option<block::Id>,
}
impl State {
pub fn block_id_prefix(&self) -> String {
self.block_id
.as_ref()
.map(block::Id::prefix)
.unwrap_or_else(|| NIL_PLACEHOLDER.to_owned())
}
}
impl fmt::Display for State {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}/{}/{}", self.height, self.round, self.step)
}
}
impl Ord for State {
fn cmp(&self, other: &State) -> Ordering {
match self.height.cmp(&other.height) {
Ordering::Greater => Ordering::Greater,
Ordering::Less => Ordering::Less,
Ordering::Equal => match self.round.cmp(&other.round) {
Ordering::Greater => Ordering::Greater,
Ordering::Less => Ordering::Less,
Ordering::Equal => self.step.cmp(&other.step),
},
}
}
}
impl PartialOrd for State {
fn partial_cmp(&self, other: &State) -> Option<Ordering> {
Some(self.cmp(other))
}
}
#[cfg(test)]
mod tests {
use core::str::FromStr;
use super::State;
use crate::{block, Hash};
#[test]
fn state_ord_test() {
let new = State {
height: block::Height::from(9001_u32),
round: block::Round::default(),
step: 0,
block_id: None,
};
let old = State {
height: block::Height::from(1001_u32),
round: block::Round::from(1_u16),
step: 0,
block_id: None,
};
let older = State {
height: block::Height::from(1001_u32),
round: block::Round::default(),
step: 0,
block_id: None,
};
let oldest = State {
height: block::Height::default(),
round: block::Round::default(),
step: 0,
block_id: None,
};
assert!(old < new);
assert!(older < old);
assert!(oldest < older);
assert!(oldest < new);
}
#[test]
fn state_deser_update_null_test() {
let state_json_string = r#"{
"height": "5",
"round": "1",
"step": 6,
"block_id": null
}"#;
let state: State = State {
height: block::Height::from(5_u32),
round: block::Round::from(1_u16),
step: 6,
block_id: None,
};
let state_from_json: State = serde_json::from_str(state_json_string).unwrap();
assert_eq!(state_from_json, state);
}
#[test]
fn state_deser_update_total_test() {
let state_json_string = r#"{
"height": "5",
"round": "1",
"step": 6,
"block_id": {
"hash": "1234567890123456789012345678901234567890123456789012345678901234",
"parts": {
"total": "1",
"hash": "1234567890123456789012345678901234567890123456789012345678901234"
}
}
}"#;
let state: State = State {
height: block::Height::from(5_u32),
round: block::Round::from(1_u16),
step: 6,
block_id: Some(block::Id {
hash: Hash::from_str(
"1234567890123456789012345678901234567890123456789012345678901234",
)
.unwrap(),
part_set_header: block::parts::Header::new(
1,
Hash::from_str(
"1234567890123456789012345678901234567890123456789012345678901234",
)
.unwrap(),
)
.unwrap(),
}),
};
let state_from_json: State = serde_json::from_str(state_json_string).unwrap();
assert_eq!(state_from_json, state);
}
}