use std::mem;
use borsh::{BorshDeserialize, BorshSerialize};
use crate::{
networking::{messages::ProgressMessage, receiving::Cacheable},
types::{
block::*,
crypto_primitives::Keypair,
data_types::*,
signed_messages::{SignedMessage, Vote},
},
};
use super::types::{Phase, PhaseCertificate};
#[derive(Clone, BorshSerialize, BorshDeserialize)]
pub enum HotStuffMessage {
Proposal(Proposal),
Nudge(Nudge),
PhaseVote(PhaseVote),
NewView(NewView),
}
impl HotStuffMessage {
pub fn chain_id(&self) -> ChainID {
match self {
HotStuffMessage::Proposal(Proposal { chain_id, .. }) => *chain_id,
HotStuffMessage::Nudge(Nudge { chain_id, .. }) => *chain_id,
HotStuffMessage::PhaseVote(PhaseVote { chain_id, .. }) => *chain_id,
HotStuffMessage::NewView(NewView { chain_id, .. }) => *chain_id,
}
}
pub fn view(&self) -> ViewNumber {
match self {
HotStuffMessage::Proposal(Proposal { view, .. }) => *view,
HotStuffMessage::Nudge(Nudge { view, .. }) => *view,
HotStuffMessage::PhaseVote(PhaseVote { view, .. }) => *view,
HotStuffMessage::NewView(NewView { view, .. }) => *view,
}
}
pub fn size(&self) -> u64 {
match self {
HotStuffMessage::Proposal(_) => mem::size_of::<Proposal>() as u64,
HotStuffMessage::Nudge(_) => mem::size_of::<Nudge>() as u64,
HotStuffMessage::PhaseVote(_) => mem::size_of::<PhaseVote>() as u64,
HotStuffMessage::NewView(_) => mem::size_of::<NewView>() as u64,
}
}
}
impl Cacheable for HotStuffMessage {
fn size(&self) -> u64 {
self.size()
}
fn view(&self) -> ViewNumber {
self.view()
}
}
impl From<Proposal> for HotStuffMessage {
fn from(proposal: Proposal) -> Self {
HotStuffMessage::Proposal(proposal)
}
}
impl From<Nudge> for HotStuffMessage {
fn from(nudge: Nudge) -> Self {
HotStuffMessage::Nudge(nudge)
}
}
impl From<PhaseVote> for HotStuffMessage {
fn from(vote: PhaseVote) -> Self {
HotStuffMessage::PhaseVote(vote)
}
}
impl From<NewView> for HotStuffMessage {
fn from(new_view: NewView) -> Self {
HotStuffMessage::NewView(new_view)
}
}
impl Into<ProgressMessage> for HotStuffMessage {
fn into(self) -> ProgressMessage {
ProgressMessage::HotStuffMessage(self)
}
}
#[derive(Clone, BorshSerialize, BorshDeserialize)]
pub struct Proposal {
pub chain_id: ChainID,
pub view: ViewNumber,
pub block: Block,
}
#[derive(Clone, BorshSerialize, BorshDeserialize)]
pub struct Nudge {
pub chain_id: ChainID,
pub view: ViewNumber,
pub justify: PhaseCertificate,
}
impl Nudge {
pub fn new(chain_id: ChainID, view: ViewNumber, justify: PhaseCertificate) -> Self {
assert!(
justify.phase.is_prepare() || justify.phase.is_precommit() || justify.phase.is_commit()
);
Self {
chain_id,
view,
justify,
}
}
}
#[derive(Clone, BorshSerialize, BorshDeserialize)]
pub struct PhaseVote {
pub chain_id: ChainID,
pub view: ViewNumber,
pub block: CryptoHash,
pub phase: Phase,
pub signature: SignatureBytes,
}
impl PhaseVote {
pub(crate) fn new(
keypair: &Keypair,
chain_id: ChainID,
view: ViewNumber,
block: CryptoHash,
phase: Phase,
) -> Self {
let message_bytes = &(chain_id, view, block, phase).try_to_vec().unwrap();
let signature = keypair.sign(message_bytes);
Self {
chain_id,
view,
block,
phase,
signature,
}
}
}
impl SignedMessage for PhaseVote {
fn message_bytes(&self) -> Vec<u8> {
(self.chain_id, self.view, self.block, self.phase)
.try_to_vec()
.unwrap()
}
fn signature_bytes(&self) -> SignatureBytes {
self.signature
}
}
impl Vote for PhaseVote {
fn chain_id(&self) -> ChainID {
self.chain_id
}
fn view(&self) -> ViewNumber {
self.view
}
}
#[derive(Clone, BorshSerialize, BorshDeserialize)]
pub struct NewView {
pub chain_id: ChainID,
pub view: ViewNumber,
pub highest_pc: PhaseCertificate,
}