use crate::{account, prelude::*, Signature, Time};
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum CommitSig {
BlockIdFlagAbsent,
BlockIdFlagCommit {
validator_address: account::Id,
timestamp: Time,
signature: Option<Signature>,
},
BlockIdFlagNil {
validator_address: account::Id,
timestamp: Time,
signature: Option<Signature>,
},
}
impl CommitSig {
pub fn validator_address(&self) -> Option<account::Id> {
match self {
Self::BlockIdFlagCommit {
validator_address, ..
} => Some(*validator_address),
Self::BlockIdFlagNil {
validator_address, ..
} => Some(*validator_address),
_ => None,
}
}
pub fn is_absent(&self) -> bool {
self == &Self::BlockIdFlagAbsent
}
pub fn is_commit(&self) -> bool {
matches!(self, Self::BlockIdFlagCommit { .. })
}
pub fn is_nil(&self) -> bool {
matches!(self, Self::BlockIdFlagNil { .. })
}
}
tendermint_pb_modules! {
use super::CommitSig;
use crate::{error::Error, prelude::*, Signature};
use num_traits::ToPrimitive;
use pb::types::{BlockIdFlag, CommitSig as RawCommitSig};
impl TryFrom<RawCommitSig> for CommitSig {
type Error = Error;
fn try_from(value: RawCommitSig) -> Result<Self, Self::Error> {
if value.block_id_flag == BlockIdFlag::Absent.to_i32().unwrap() {
if value.timestamp.is_some() {
let timestamp = value.timestamp.unwrap();
if timestamp.nanos != 0 || timestamp.seconds != -62135596800 {
return Err(Error::invalid_timestamp(
"absent commitsig has non-zero timestamp".to_string(),
));
}
}
if !value.signature.is_empty() {
return Err(Error::invalid_signature(
"expected empty signature for absent commitsig".to_string(),
));
}
return Ok(CommitSig::BlockIdFlagAbsent);
}
if value.block_id_flag == BlockIdFlag::Commit.to_i32().unwrap() {
if value.signature.is_empty() {
return Err(Error::invalid_signature(
"expected non-empty signature for regular commitsig".to_string(),
));
}
if value.validator_address.is_empty() {
return Err(Error::invalid_validator_address());
}
let timestamp = value
.timestamp
.ok_or_else(Error::missing_timestamp)?
.try_into()?;
return Ok(CommitSig::BlockIdFlagCommit {
validator_address: value.validator_address.try_into()?,
timestamp,
signature: Signature::new(value.signature)?,
});
}
if value.block_id_flag == BlockIdFlag::Nil.to_i32().unwrap() {
if value.signature.is_empty() {
return Err(Error::invalid_signature(
"nil commitsig has no signature".to_string(),
));
}
if value.validator_address.is_empty() {
return Err(Error::invalid_validator_address());
}
return Ok(CommitSig::BlockIdFlagNil {
validator_address: value.validator_address.try_into()?,
timestamp: value
.timestamp
.ok_or_else(Error::missing_timestamp)?
.try_into()?,
signature: Signature::new(value.signature)?,
});
}
Err(Error::block_id_flag())
}
}
impl From<CommitSig> for RawCommitSig {
fn from(commit: CommitSig) -> RawCommitSig {
match commit {
CommitSig::BlockIdFlagAbsent => RawCommitSig {
block_id_flag: BlockIdFlag::Absent.to_i32().unwrap(),
validator_address: Vec::new(),
timestamp: None,
signature: Vec::new(),
},
CommitSig::BlockIdFlagNil {
validator_address,
timestamp,
signature,
} => RawCommitSig {
block_id_flag: BlockIdFlag::Nil.to_i32().unwrap(),
validator_address: validator_address.into(),
timestamp: Some(timestamp.into()),
signature: signature.map(|s| s.to_bytes()).unwrap_or_default(),
},
CommitSig::BlockIdFlagCommit {
validator_address,
timestamp,
signature,
} => RawCommitSig {
block_id_flag: BlockIdFlag::Commit.to_i32().unwrap(),
validator_address: validator_address.into(),
timestamp: Some(timestamp.into()),
signature: signature.map(|s| s.to_bytes()).unwrap_or_default(),
},
}
}
}
}