tendermint/proposal/
canonical_proposal.rsuse super::Type;
use crate::{
block::{Height, Id as BlockId, Round},
chain::Id as ChainId,
prelude::*,
Time,
};
#[derive(Clone, PartialEq, Eq)]
pub struct CanonicalProposal {
pub msg_type: Type,
pub height: Height,
pub round: Round,
pub pol_round: Option<Round>,
pub block_id: Option<BlockId>,
pub timestamp: Option<Time>,
pub chain_id: ChainId,
}
tendermint_pb_modules! {
use crate::{
block::{Id as BlockId, Round},
chain::Id as ChainId,
error::Error,
prelude::*,
};
use super::CanonicalProposal;
use pb::types::CanonicalProposal as RawCanonicalProposal;
impl Protobuf<RawCanonicalProposal> for CanonicalProposal {}
impl TryFrom<RawCanonicalProposal> for CanonicalProposal {
type Error = Error;
fn try_from(value: RawCanonicalProposal) -> Result<Self, Self::Error> {
if value.pol_round < -1 {
return Err(Error::negative_pol_round());
}
let round = Round::try_from(i32::try_from(value.round).map_err(Error::integer_overflow)?)?;
let pol_round = match value.pol_round {
-1 => None,
n => Some(Round::try_from(
i32::try_from(n).map_err(Error::integer_overflow)?,
)?),
};
let block_id = value.block_id.filter(|i| !i.hash.is_empty());
Ok(CanonicalProposal {
msg_type: value.r#type.try_into()?,
height: value.height.try_into()?,
round,
pol_round,
block_id: block_id.map(TryInto::try_into).transpose()?,
timestamp: value.timestamp.map(|t| t.try_into()).transpose()?,
chain_id: ChainId::try_from(value.chain_id).unwrap(),
})
}
}
impl From<CanonicalProposal> for RawCanonicalProposal {
fn from(value: CanonicalProposal) -> Self {
let block_id = value.block_id.filter(|i| i != &BlockId::default());
RawCanonicalProposal {
r#type: value.msg_type.into(),
height: value.height.into(),
round: i32::from(value.round) as i64,
pol_round: match value.pol_round {
None => -1,
Some(p) => i32::from(p) as i64,
},
block_id: block_id.map(Into::into),
timestamp: value.timestamp.map(Into::into),
chain_id: value.chain_id.as_str().to_string(),
}
}
}
}
impl CanonicalProposal {
pub fn new(proposal: super::Proposal, chain_id: ChainId) -> CanonicalProposal {
CanonicalProposal {
msg_type: proposal.msg_type,
height: proposal.height,
round: proposal.round,
pol_round: proposal.pol_round,
block_id: proposal.block_id,
timestamp: proposal.timestamp,
chain_id,
}
}
}
#[cfg(test)]
mod tests {
tendermint_pb_modules! {
use pb::types::{
CanonicalBlockId as RawCanonicalBlockId,
CanonicalPartSetHeader as RawCanonicalPartSetHeader,
CanonicalProposal as RawCanonicalProposal,
};
use crate::{
prelude::*,
proposal::{canonical_proposal::CanonicalProposal, Type},
};
#[test]
fn canonical_proposal_domain_checks() {
let proto_cp = RawCanonicalProposal {
r#type: 32,
height: 2,
round: 4,
pol_round: -1,
block_id: Some(RawCanonicalBlockId {
hash: vec![],
part_set_header: Some(RawCanonicalPartSetHeader {
total: 1,
hash: vec![1],
}),
}),
timestamp: None,
chain_id: "testchain".to_string(),
};
let cp = CanonicalProposal::try_from(proto_cp).unwrap();
assert_eq!(cp.msg_type, Type::Proposal);
assert!(cp.pol_round.is_none());
assert!(cp.block_id.is_none());
}
}
}