use std::{
fmt::Debug,
hash::Hash,
marker::PhantomData,
ops::{Deref, DerefMut},
};
use committable::{Commitment, Committable};
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use utils::anytrace::*;
use vbs::version::Version;
use crate::{
data::{Leaf, Leaf2},
message::UpgradeLock,
traits::{
node_implementation::{ConsensusTime, NodeType, Versions},
signature_key::SignatureKey,
},
vid::VidCommitment,
vote::{HasViewNumber, Vote},
};
pub(crate) trait QuorumMarker {}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Hash, Eq)]
#[serde(bound(deserialize = ""))]
pub struct QuorumData<TYPES: NodeType> {
pub leaf_commit: Commitment<Leaf<TYPES>>,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Hash, Eq)]
#[serde(bound(deserialize = ""))]
pub struct QuorumData2<TYPES: NodeType> {
pub leaf_commit: Commitment<Leaf2<TYPES>>,
pub epoch: TYPES::Epoch,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Hash, Eq)]
#[serde(bound(deserialize = ""))]
pub struct NextEpochQuorumData2<TYPES: NodeType>(QuorumData2<TYPES>);
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Hash, Eq)]
pub struct DaData {
pub payload_commit: VidCommitment,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Hash, Eq)]
pub struct DaData2<TYPES: NodeType> {
pub payload_commit: VidCommitment,
pub epoch: TYPES::Epoch,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Hash, Eq)]
pub struct TimeoutData<TYPES: NodeType> {
pub view: TYPES::View,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Hash, Eq)]
pub struct TimeoutData2<TYPES: NodeType> {
pub view: TYPES::View,
pub epoch: TYPES::Epoch,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Hash, Eq)]
pub struct ViewSyncPreCommitData<TYPES: NodeType> {
pub relay: u64,
pub round: TYPES::View,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Hash, Eq)]
pub struct ViewSyncPreCommitData2<TYPES: NodeType> {
pub relay: u64,
pub round: TYPES::View,
pub epoch: TYPES::Epoch,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Hash, Eq)]
pub struct ViewSyncCommitData<TYPES: NodeType> {
pub relay: u64,
pub round: TYPES::View,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Hash, Eq)]
pub struct ViewSyncCommitData2<TYPES: NodeType> {
pub relay: u64,
pub round: TYPES::View,
pub epoch: TYPES::Epoch,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Hash, Eq)]
pub struct ViewSyncFinalizeData<TYPES: NodeType> {
pub relay: u64,
pub round: TYPES::View,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Hash, Eq)]
pub struct ViewSyncFinalizeData2<TYPES: NodeType> {
pub relay: u64,
pub round: TYPES::View,
pub epoch: TYPES::Epoch,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Hash, Eq)]
pub struct UpgradeProposalData<TYPES: NodeType + DeserializeOwned> {
pub old_version: Version,
pub new_version: Version,
pub decide_by: TYPES::View,
pub new_version_hash: Vec<u8>,
pub old_version_last_view: TYPES::View,
pub new_version_first_view: TYPES::View,
}
pub struct UpgradeData2<TYPES: NodeType> {
pub old_version: Version,
pub new_version: Version,
pub hash: Vec<u8>,
pub epoch: TYPES::Epoch,
}
pub trait Voteable<TYPES: NodeType>:
sealed::Sealed + Committable + Clone + Serialize + Debug + PartialEq + Hash + Eq
{
}
pub trait Voteable2<TYPES: NodeType>:
sealed::Sealed + HasEpoch<TYPES> + Committable + Clone + Serialize + Debug + PartialEq + Hash + Eq
{
}
mod sealed {
use committable::Committable;
pub trait Sealed {}
impl<C: Committable> Sealed for C {}
}
impl<T: NodeType> QuorumMarker for QuorumData<T> {}
impl<T: NodeType> QuorumMarker for QuorumData2<T> {}
impl<T: NodeType> QuorumMarker for NextEpochQuorumData2<T> {}
impl<T: NodeType> QuorumMarker for TimeoutData<T> {}
impl<T: NodeType> QuorumMarker for TimeoutData2<T> {}
impl<T: NodeType> QuorumMarker for ViewSyncPreCommitData<T> {}
impl<T: NodeType> QuorumMarker for ViewSyncCommitData<T> {}
impl<T: NodeType> QuorumMarker for ViewSyncFinalizeData<T> {}
impl<T: NodeType> QuorumMarker for ViewSyncPreCommitData2<T> {}
impl<T: NodeType> QuorumMarker for ViewSyncCommitData2<T> {}
impl<T: NodeType> QuorumMarker for ViewSyncFinalizeData2<T> {}
impl<T: NodeType + DeserializeOwned> QuorumMarker for UpgradeProposalData<T> {}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Hash, Eq)]
pub struct SimpleVote<TYPES: NodeType, DATA: Voteable<TYPES>> {
pub signature: (
TYPES::SignatureKey,
<TYPES::SignatureKey as SignatureKey>::PureAssembledSignatureType,
),
pub data: DATA,
pub view_number: TYPES::View,
}
impl<TYPES: NodeType, DATA: Voteable<TYPES> + 'static> HasViewNumber<TYPES>
for SimpleVote<TYPES, DATA>
{
fn view_number(&self) -> <TYPES as NodeType>::View {
self.view_number
}
}
impl<TYPES: NodeType, DATA: Voteable<TYPES> + 'static> Vote<TYPES> for SimpleVote<TYPES, DATA> {
type Commitment = DATA;
fn signing_key(&self) -> <TYPES as NodeType>::SignatureKey {
self.signature.0.clone()
}
fn signature(&self) -> <TYPES::SignatureKey as SignatureKey>::PureAssembledSignatureType {
self.signature.1.clone()
}
fn date(&self) -> &DATA {
&self.data
}
fn data_commitment(&self) -> Commitment<DATA> {
self.data.commit()
}
}
impl<TYPES: NodeType, DATA: Voteable<TYPES> + 'static> SimpleVote<TYPES, DATA> {
pub async fn create_signed_vote<V: Versions>(
data: DATA,
view: TYPES::View,
pub_key: &TYPES::SignatureKey,
private_key: &<TYPES::SignatureKey as SignatureKey>::PrivateKey,
upgrade_lock: &UpgradeLock<TYPES, V>,
) -> Result<Self> {
let commit = VersionedVoteData::new(data.clone(), view, upgrade_lock)
.await?
.commit();
let signature = (
pub_key.clone(),
TYPES::SignatureKey::sign(private_key, commit.as_ref())
.wrap()
.context(error!("Failed to sign vote"))?,
);
Ok(Self {
signature,
data,
view_number: view,
})
}
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Hash, Eq)]
pub struct VersionedVoteData<TYPES: NodeType, DATA: Voteable<TYPES>, V: Versions> {
data: DATA,
view: TYPES::View,
version: Version,
_pd: PhantomData<V>,
}
impl<TYPES: NodeType, DATA: Voteable<TYPES>, V: Versions> VersionedVoteData<TYPES, DATA, V> {
pub async fn new(
data: DATA,
view: TYPES::View,
upgrade_lock: &UpgradeLock<TYPES, V>,
) -> Result<Self> {
let version = upgrade_lock.version(view).await?;
Ok(Self {
data,
view,
version,
_pd: PhantomData,
})
}
pub async fn new_infallible(
data: DATA,
view: TYPES::View,
upgrade_lock: &UpgradeLock<TYPES, V>,
) -> Self {
let version = upgrade_lock.version_infallible(view).await;
Self {
data,
view,
version,
_pd: PhantomData,
}
}
}
impl<TYPES: NodeType, DATA: Voteable<TYPES>, V: Versions> Committable
for VersionedVoteData<TYPES, DATA, V>
{
fn commit(&self) -> Commitment<Self> {
committable::RawCommitmentBuilder::new("Vote")
.var_size_bytes(self.data.commit().as_ref())
.u64(*self.view)
.finalize()
}
}
impl<TYPES: NodeType> Committable for QuorumData<TYPES> {
fn commit(&self) -> Commitment<Self> {
committable::RawCommitmentBuilder::new("Quorum data")
.var_size_bytes(self.leaf_commit.as_ref())
.finalize()
}
}
impl<TYPES: NodeType> Committable for QuorumData2<TYPES> {
fn commit(&self) -> Commitment<Self> {
let QuorumData2 {
leaf_commit,
epoch: _,
} = self;
committable::RawCommitmentBuilder::new("Quorum data")
.var_size_bytes(leaf_commit.as_ref())
.finalize()
}
}
impl<TYPES: NodeType> Committable for NextEpochQuorumData2<TYPES> {
fn commit(&self) -> Commitment<Self> {
committable::RawCommitmentBuilder::new("Quorum data")
.var_size_bytes(self.leaf_commit.as_ref())
.finalize()
}
}
impl<TYPES: NodeType> Committable for TimeoutData<TYPES> {
fn commit(&self) -> Commitment<Self> {
committable::RawCommitmentBuilder::new("Timeout data")
.u64(*self.view)
.finalize()
}
}
impl<TYPES: NodeType> Committable for TimeoutData2<TYPES> {
fn commit(&self) -> Commitment<Self> {
let TimeoutData2 { view, epoch: _ } = self;
committable::RawCommitmentBuilder::new("Timeout data")
.u64(**view)
.finalize()
}
}
impl Committable for DaData {
fn commit(&self) -> Commitment<Self> {
committable::RawCommitmentBuilder::new("DA data")
.var_size_bytes(self.payload_commit.as_ref())
.finalize()
}
}
impl<TYPES: NodeType> Committable for DaData2<TYPES> {
fn commit(&self) -> Commitment<Self> {
let DaData2 {
payload_commit,
epoch: _,
} = self;
committable::RawCommitmentBuilder::new("DA data")
.var_size_bytes(payload_commit.as_ref())
.finalize()
}
}
impl<TYPES: NodeType> Committable for UpgradeProposalData<TYPES> {
fn commit(&self) -> Commitment<Self> {
let builder = committable::RawCommitmentBuilder::new("Upgrade data");
builder
.u64(*self.decide_by)
.u64(*self.new_version_first_view)
.u64(*self.old_version_last_view)
.var_size_bytes(self.new_version_hash.as_slice())
.u16(self.new_version.minor)
.u16(self.new_version.major)
.u16(self.old_version.minor)
.u16(self.old_version.major)
.finalize()
}
}
impl<TYPES: NodeType> Committable for UpgradeData2<TYPES> {
fn commit(&self) -> Commitment<Self> {
let UpgradeData2 {
old_version,
new_version,
hash,
epoch,
} = self;
committable::RawCommitmentBuilder::new("Upgrade data")
.u16(old_version.minor)
.u16(old_version.major)
.u16(new_version.minor)
.u16(new_version.major)
.var_size_bytes(hash.as_slice())
.u64(**epoch)
.finalize()
}
}
fn view_and_relay_commit<TYPES: NodeType, T: Committable>(
view: TYPES::View,
relay: u64,
tag: &str,
) -> Commitment<T> {
let builder = committable::RawCommitmentBuilder::new(tag);
builder.u64(*view).u64(relay).finalize()
}
impl<TYPES: NodeType> Committable for ViewSyncPreCommitData<TYPES> {
fn commit(&self) -> Commitment<Self> {
view_and_relay_commit::<TYPES, Self>(self.round, self.relay, "View Sync Precommit")
}
}
impl<TYPES: NodeType> Committable for ViewSyncPreCommitData2<TYPES> {
fn commit(&self) -> Commitment<Self> {
let ViewSyncPreCommitData2 {
relay,
round,
epoch: _,
} = self;
view_and_relay_commit::<TYPES, Self>(*round, *relay, "View Sync Precommit")
}
}
impl<TYPES: NodeType> Committable for ViewSyncFinalizeData<TYPES> {
fn commit(&self) -> Commitment<Self> {
view_and_relay_commit::<TYPES, Self>(self.round, self.relay, "View Sync Finalize")
}
}
impl<TYPES: NodeType> Committable for ViewSyncFinalizeData2<TYPES> {
fn commit(&self) -> Commitment<Self> {
let ViewSyncFinalizeData2 {
relay,
round,
epoch: _,
} = self;
view_and_relay_commit::<TYPES, Self>(*round, *relay, "View Sync Finalize")
}
}
impl<TYPES: NodeType> Committable for ViewSyncCommitData<TYPES> {
fn commit(&self) -> Commitment<Self> {
view_and_relay_commit::<TYPES, Self>(self.round, self.relay, "View Sync Commit")
}
}
impl<TYPES: NodeType> Committable for ViewSyncCommitData2<TYPES> {
fn commit(&self) -> Commitment<Self> {
let ViewSyncCommitData2 {
relay,
round,
epoch: _,
} = self;
view_and_relay_commit::<TYPES, Self>(*round, *relay, "View Sync Commit")
}
}
pub trait HasEpoch<TYPES: NodeType> {
fn epoch(&self) -> TYPES::Epoch;
}
#[macro_export]
macro_rules! impl_has_epoch {
($($t:ty),*) => {
$(
impl<TYPES: NodeType> HasEpoch<TYPES> for $t {
fn epoch(&self) -> TYPES::Epoch {
self.epoch
}
}
)*
};
}
impl_has_epoch!(
QuorumData2<TYPES>,
NextEpochQuorumData2<TYPES>,
DaData2<TYPES>,
TimeoutData2<TYPES>,
ViewSyncPreCommitData2<TYPES>,
ViewSyncCommitData2<TYPES>,
ViewSyncFinalizeData2<TYPES>
);
impl<TYPES: NodeType, DATA: Voteable<TYPES> + HasEpoch<TYPES>> HasEpoch<TYPES>
for SimpleVote<TYPES, DATA>
{
fn epoch(&self) -> TYPES::Epoch {
self.data.epoch()
}
}
impl<
TYPES: NodeType,
V: sealed::Sealed + Committable + Clone + Serialize + Debug + PartialEq + Hash + Eq,
> Voteable<TYPES> for V
{
}
impl<
TYPES: NodeType,
V: sealed::Sealed
+ HasEpoch<TYPES>
+ Committable
+ Clone
+ Serialize
+ Debug
+ PartialEq
+ Hash
+ Eq,
> Voteable2<TYPES> for V
{
}
impl<TYPES: NodeType> QuorumVote<TYPES> {
pub fn to_vote2(self) -> QuorumVote2<TYPES> {
let bytes: [u8; 32] = self.data.leaf_commit.into();
let signature = self.signature;
let data = QuorumData2 {
leaf_commit: Commitment::from_raw(bytes),
epoch: TYPES::Epoch::genesis(),
};
let view_number = self.view_number;
SimpleVote {
signature,
data,
view_number,
}
}
}
impl<TYPES: NodeType> QuorumVote2<TYPES> {
pub fn to_vote(self) -> QuorumVote<TYPES> {
let bytes: [u8; 32] = self.data.leaf_commit.into();
let signature = self.signature.clone();
let data = QuorumData {
leaf_commit: Commitment::from_raw(bytes),
};
let view_number = self.view_number;
SimpleVote {
signature,
data,
view_number,
}
}
}
impl<TYPES: NodeType> DaVote<TYPES> {
pub fn to_vote2(self) -> DaVote2<TYPES> {
let signature = self.signature;
let data = DaData2 {
payload_commit: self.data.payload_commit,
epoch: TYPES::Epoch::new(0),
};
let view_number = self.view_number;
SimpleVote {
signature,
data,
view_number,
}
}
}
impl<TYPES: NodeType> DaVote2<TYPES> {
pub fn to_vote(self) -> DaVote<TYPES> {
let signature = self.signature;
let data = DaData {
payload_commit: self.data.payload_commit,
};
let view_number = self.view_number;
SimpleVote {
signature,
data,
view_number,
}
}
}
impl<TYPES: NodeType> TimeoutVote<TYPES> {
pub fn to_vote2(self) -> TimeoutVote2<TYPES> {
let signature = self.signature;
let data = TimeoutData2 {
view: self.data.view,
epoch: TYPES::Epoch::new(0),
};
let view_number = self.view_number;
SimpleVote {
signature,
data,
view_number,
}
}
}
impl<TYPES: NodeType> TimeoutVote2<TYPES> {
pub fn to_vote(self) -> TimeoutVote<TYPES> {
let signature = self.signature;
let data = TimeoutData {
view: self.data.view,
};
let view_number = self.view_number;
SimpleVote {
signature,
data,
view_number,
}
}
}
impl<TYPES: NodeType> ViewSyncPreCommitVote<TYPES> {
pub fn to_vote2(self) -> ViewSyncPreCommitVote2<TYPES> {
let signature = self.signature;
let data = ViewSyncPreCommitData2 {
relay: self.data.relay,
round: self.data.round,
epoch: TYPES::Epoch::new(0),
};
let view_number = self.view_number;
SimpleVote {
signature,
data,
view_number,
}
}
}
impl<TYPES: NodeType> ViewSyncPreCommitVote2<TYPES> {
pub fn to_vote(self) -> ViewSyncPreCommitVote<TYPES> {
let signature = self.signature;
let data = ViewSyncPreCommitData {
relay: self.data.relay,
round: self.data.round,
};
let view_number = self.view_number;
SimpleVote {
signature,
data,
view_number,
}
}
}
impl<TYPES: NodeType> ViewSyncCommitVote<TYPES> {
pub fn to_vote2(self) -> ViewSyncCommitVote2<TYPES> {
let signature = self.signature;
let data = ViewSyncCommitData2 {
relay: self.data.relay,
round: self.data.round,
epoch: TYPES::Epoch::new(0),
};
let view_number = self.view_number;
SimpleVote {
signature,
data,
view_number,
}
}
}
impl<TYPES: NodeType> ViewSyncCommitVote2<TYPES> {
pub fn to_vote(self) -> ViewSyncCommitVote<TYPES> {
let signature = self.signature;
let data = ViewSyncCommitData {
relay: self.data.relay,
round: self.data.round,
};
let view_number = self.view_number;
SimpleVote {
signature,
data,
view_number,
}
}
}
impl<TYPES: NodeType> ViewSyncFinalizeVote<TYPES> {
pub fn to_vote2(self) -> ViewSyncFinalizeVote2<TYPES> {
let signature = self.signature;
let data = ViewSyncFinalizeData2 {
relay: self.data.relay,
round: self.data.round,
epoch: TYPES::Epoch::new(0),
};
let view_number = self.view_number;
SimpleVote {
signature,
data,
view_number,
}
}
}
impl<TYPES: NodeType> ViewSyncFinalizeVote2<TYPES> {
pub fn to_vote(self) -> ViewSyncFinalizeVote<TYPES> {
let signature = self.signature;
let data = ViewSyncFinalizeData {
relay: self.data.relay,
round: self.data.round,
};
let view_number = self.view_number;
SimpleVote {
signature,
data,
view_number,
}
}
}
pub type QuorumVote<TYPES> = SimpleVote<TYPES, QuorumData<TYPES>>;
pub type QuorumVote2<TYPES> = SimpleVote<TYPES, QuorumData2<TYPES>>;
pub type NextEpochQuorumVote2<TYPES> = SimpleVote<TYPES, NextEpochQuorumData2<TYPES>>;
pub type DaVote<TYPES> = SimpleVote<TYPES, DaData>;
pub type DaVote2<TYPES> = SimpleVote<TYPES, DaData2<TYPES>>;
pub type TimeoutVote<TYPES> = SimpleVote<TYPES, TimeoutData<TYPES>>;
pub type TimeoutVote2<TYPES> = SimpleVote<TYPES, TimeoutData2<TYPES>>;
pub type ViewSyncPreCommitVote<TYPES> = SimpleVote<TYPES, ViewSyncPreCommitData<TYPES>>;
pub type ViewSyncPreCommitVote2<TYPES> = SimpleVote<TYPES, ViewSyncPreCommitData2<TYPES>>;
pub type ViewSyncFinalizeVote<TYPES> = SimpleVote<TYPES, ViewSyncFinalizeData<TYPES>>;
pub type ViewSyncFinalizeVote2<TYPES> = SimpleVote<TYPES, ViewSyncFinalizeData2<TYPES>>;
pub type ViewSyncCommitVote<TYPES> = SimpleVote<TYPES, ViewSyncCommitData<TYPES>>;
pub type ViewSyncCommitVote2<TYPES> = SimpleVote<TYPES, ViewSyncCommitData2<TYPES>>;
pub type UpgradeVote<TYPES> = SimpleVote<TYPES, UpgradeProposalData<TYPES>>;
pub type UpgradeVote2<TYPES> = SimpleVote<TYPES, UpgradeData2<TYPES>>;
impl<TYPES: NodeType> Deref for NextEpochQuorumData2<TYPES> {
type Target = QuorumData2<TYPES>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<TYPES: NodeType> DerefMut for NextEpochQuorumData2<TYPES> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<TYPES: NodeType> From<QuorumData2<TYPES>> for NextEpochQuorumData2<TYPES> {
fn from(data: QuorumData2<TYPES>) -> Self {
Self(QuorumData2 {
epoch: data.epoch,
leaf_commit: data.leaf_commit,
})
}
}
impl<TYPES: NodeType> From<QuorumVote2<TYPES>> for NextEpochQuorumVote2<TYPES> {
fn from(qvote: QuorumVote2<TYPES>) -> Self {
Self {
data: qvote.data.into(),
view_number: qvote.view_number,
signature: qvote.signature.clone(),
}
}
}