use std::{collections::BTreeSet, fmt};
use datasize::DataSize;
use serde::{Deserialize, Serialize};
use casper_types::Timestamp;
use crate::components::consensus::{
consensus_protocol::ProposedBlock, protocols::zug::RoundId, traits::Context,
utils::ValidatorIndex,
};
#[derive(Clone, Hash, Serialize, Deserialize, Debug, PartialEq, Eq, DataSize)]
#[serde(bound(
serialize = "C::Hash: Serialize",
deserialize = "C::Hash: Deserialize<'de>",
))]
pub(crate) struct Proposal<C>
where
C: Context,
{
pub(super) timestamp: Timestamp,
pub(super) maybe_block: Option<C::ConsensusValue>,
pub(super) maybe_parent_round_id: Option<RoundId>,
pub(super) inactive: Option<BTreeSet<ValidatorIndex>>,
}
impl<C: Context> Proposal<C> {
pub(super) fn dummy(timestamp: Timestamp, parent_round_id: RoundId) -> Self {
Proposal {
timestamp,
maybe_block: None,
maybe_parent_round_id: Some(parent_round_id),
inactive: None,
}
}
pub(super) fn with_block(
proposed_block: &ProposedBlock<C>,
maybe_parent_round_id: Option<RoundId>,
inactive: impl Iterator<Item = ValidatorIndex>,
) -> Self {
Proposal {
maybe_block: Some(proposed_block.value().clone()),
timestamp: proposed_block.context().timestamp(),
maybe_parent_round_id,
inactive: maybe_parent_round_id.map(|_| inactive.collect()),
}
}
#[cfg(test)] pub(super) fn hash(&self) -> C::Hash {
let serialized = bincode::serialize(&self).expect("failed to serialize fields");
<C as Context>::hash(&serialized)
}
}
#[derive(Clone, Hash, Debug, PartialEq, Eq, DataSize)]
pub(crate) struct HashedProposal<C>
where
C: Context,
{
hash: C::Hash,
proposal: Proposal<C>,
}
impl<C: Context> HashedProposal<C> {
pub(crate) fn new(proposal: Proposal<C>) -> Self {
let serialized = bincode::serialize(&proposal).expect("failed to serialize fields");
let hash = <C as Context>::hash(&serialized);
HashedProposal { hash, proposal }
}
pub(crate) fn hash(&self) -> &C::Hash {
&self.hash
}
pub(crate) fn inner(&self) -> &Proposal<C> {
&self.proposal
}
pub(crate) fn into_inner(self) -> Proposal<C> {
self.proposal
}
pub(crate) fn maybe_block(&self) -> Option<&C::ConsensusValue> {
self.proposal.maybe_block.as_ref()
}
pub(crate) fn timestamp(&self) -> Timestamp {
self.proposal.timestamp
}
pub(crate) fn inactive(&self) -> Option<&BTreeSet<ValidatorIndex>> {
self.proposal.inactive.as_ref()
}
pub(crate) fn maybe_parent_round_id(&self) -> Option<RoundId> {
self.proposal.maybe_parent_round_id
}
}
impl<C: Context> fmt::Display for Proposal<C> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.maybe_block {
None => write!(f, "dummy proposal at {}", self.timestamp),
Some(block) => write!(f, "proposal at {}: {}", self.timestamp, block),
}
}
}
impl<C: Context> fmt::Display for HashedProposal<C> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}, hash {}", self.proposal, self.hash)
}
}