use bincode::Options;
use lazy_static::lazy_static;
use serde_derive::{Deserialize, Serialize};
use sha2::{Digest as _, Sha256};
use crate::common::{
signed::InauthenticMessage, ClientId, Digest, OpNumber, Opaque, ReplicaId, RequestNumber,
SignedMessage, VerifyingKey, ViewNumber,
};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ToReplica {
Request(Request),
Generic(Generic),
VoteGeneric(SignedMessage<VoteGeneric>),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Request {
pub op: Opaque,
pub request_number: RequestNumber,
pub client_id: ClientId,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Generic {
pub view_number: ViewNumber,
pub node: GenericNode,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct VoteGeneric {
pub view_number: ViewNumber,
pub node: Digest,
pub replica_id: ReplicaId,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Reply {
pub request_number: RequestNumber,
pub result: Opaque,
pub replica_id: ReplicaId,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct GenericNode {
pub parent: Digest,
pub command: Vec<Request>,
pub justify: QuorumCertification,
pub height: OpNumber,
}
lazy_static! {
pub static ref GENESIS: GenericNode = GenericNode::default();
}
impl GenericNode {
pub fn create_leaf(
parent: &Digest,
command: Vec<Request>,
qc: QuorumCertification,
height: OpNumber,
) -> Self {
Self {
parent: *parent,
command,
justify: qc,
height,
}
}
pub fn digest(&self) -> Digest {
Sha256::digest(bincode::options().serialize(self).unwrap()).into()
}
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct QuorumCertification {
pub view_number: ViewNumber,
pub node: Digest,
pub signature: Vec<(ReplicaId, SignedMessage<VoteGeneric>)>,
}
impl QuorumCertification {
pub fn verify<'a>(
&'a self,
verifying_key: impl Fn(ReplicaId) -> &'a VerifyingKey,
threshold: usize,
) -> Result<(), InauthenticMessage> {
assert!(threshold > 0);
if self.node == GENESIS.justify.node {
return Ok(());
}
if self.signature.len() < threshold {
return Err(InauthenticMessage);
}
for (replica, vote) in self.signature.iter().cloned() {
if let Ok(verified) = vote.verify(verifying_key(replica)) {
if verified.view_number != self.view_number || verified.node != self.node {
return Err(InauthenticMessage); }
} else {
return Err(InauthenticMessage);
}
}
Ok(())
}
}