use std::borrow::Cow;
use linera_base::{
crypto::{ValidatorPublicKey, ValidatorSignature},
data_types::Round,
hashed::Hashed,
};
use linera_execution::committee::Committee;
use serde::{Deserialize, Serialize};
use super::{CertificateValue, GenericCertificate};
use crate::{
data_types::{check_signatures, LiteValue, LiteVote},
ChainError,
};
#[derive(Clone, Debug, Serialize, Deserialize)]
#[cfg_attr(with_testing, derive(Eq, PartialEq))]
pub struct LiteCertificate<'a> {
pub value: LiteValue,
pub round: Round,
pub signatures: Cow<'a, [(ValidatorPublicKey, ValidatorSignature)]>,
}
impl<'a> LiteCertificate<'a> {
pub fn new(
value: LiteValue,
round: Round,
mut signatures: Vec<(ValidatorPublicKey, ValidatorSignature)>,
) -> Self {
signatures.sort_by_key(|&(validator_name, _)| validator_name);
let signatures = Cow::Owned(signatures);
Self {
value,
round,
signatures,
}
}
pub fn try_from_votes(votes: impl IntoIterator<Item = LiteVote>) -> Option<Self> {
let mut votes = votes.into_iter();
let LiteVote {
value,
round,
public_key,
signature,
} = votes.next()?;
let mut signatures = vec![(public_key, signature)];
for vote in votes {
if vote.value.value_hash != value.value_hash || vote.round != round {
return None;
}
signatures.push((vote.public_key, vote.signature));
}
Some(LiteCertificate::new(value, round, signatures))
}
pub fn check(&self, committee: &Committee) -> Result<&LiteValue, ChainError> {
check_signatures(
self.value.value_hash,
self.value.kind,
self.round,
&self.signatures,
committee,
)?;
Ok(&self.value)
}
pub fn check_value<T: CertificateValue>(&self, value: &Hashed<T>) -> bool {
self.value.chain_id == value.inner().chain_id()
&& T::KIND == self.value.kind
&& self.value.value_hash == value.hash()
}
pub fn with_value<T: CertificateValue>(
self,
value: Hashed<T>,
) -> Option<GenericCertificate<T>> {
if self.value.chain_id != value.inner().chain_id()
|| T::KIND != self.value.kind
|| self.value.value_hash != value.hash()
{
return None;
}
Some(GenericCertificate::new(
value,
self.round,
self.signatures.into_owned(),
))
}
pub fn cloned(&self) -> LiteCertificate<'static> {
LiteCertificate {
value: self.value.clone(),
round: self.round,
signatures: Cow::Owned(self.signatures.clone().into_owned()),
}
}
}