use std::{fmt::Debug, hash::Hash, marker::PhantomData};
use anyhow::Result;
use committable::{Commitment, Committable};
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use vbs::version::{StaticVersionType, Version};
use crate::{
data::Leaf,
message::UpgradeLock,
traits::{
node_implementation::{NodeType, Versions},
signature_key::SignatureKey,
},
vid::VidCommitment,
vote::{HasViewNumber, Vote},
};
#[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)]
pub struct DaData {
pub payload_commit: VidCommitment,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Hash, Eq)]
pub struct TimeoutData<TYPES: NodeType> {
pub view: TYPES::Time,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Hash, Eq)]
pub struct VidData {
pub payload_commit: VidCommitment,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Hash, Eq)]
pub struct ViewSyncPreCommitData<TYPES: NodeType> {
pub relay: u64,
pub round: TYPES::Time,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Hash, Eq)]
pub struct ViewSyncCommitData<TYPES: NodeType> {
pub relay: u64,
pub round: TYPES::Time,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Hash, Eq)]
pub struct ViewSyncFinalizeData<TYPES: NodeType> {
pub relay: u64,
pub round: TYPES::Time,
}
#[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::Time,
pub new_version_hash: Vec<u8>,
pub old_version_last_view: TYPES::Time,
pub new_version_first_view: TYPES::Time,
}
pub trait Voteable:
sealed::Sealed + Committable + Clone + Serialize + Debug + PartialEq + Hash + Eq
{
}
mod sealed {
use committable::Committable;
pub trait Sealed {}
impl<C: Committable> Sealed for C {}
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Hash, Eq)]
pub struct SimpleVote<TYPES: NodeType, DATA: Voteable> {
pub signature: (
TYPES::SignatureKey,
<TYPES::SignatureKey as SignatureKey>::PureAssembledSignatureType,
),
pub data: DATA,
pub view_number: TYPES::Time,
}
impl<TYPES: NodeType, DATA: Voteable + 'static> HasViewNumber<TYPES> for SimpleVote<TYPES, DATA> {
fn view_number(&self) -> <TYPES as NodeType>::Time {
self.view_number
}
}
impl<TYPES: NodeType, DATA: Voteable + '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 date_commitment(&self) -> Commitment<DATA> {
self.data.commit()
}
}
impl<TYPES: NodeType, DATA: Voteable + 'static> SimpleVote<TYPES, DATA> {
pub async fn create_signed_vote<V: Versions>(
data: DATA,
view: TYPES::Time,
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())?,
);
Ok(Self {
signature,
data,
view_number: view,
})
}
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Hash, Eq)]
pub struct VersionedVoteData<TYPES: NodeType, DATA: Voteable, V: Versions> {
data: DATA,
view: TYPES::Time,
version: Version,
_pd: PhantomData<V>,
}
impl<TYPES: NodeType, DATA: Voteable, V: Versions> VersionedVoteData<TYPES, DATA, V> {
pub async fn new(
data: DATA,
view: TYPES::Time,
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::Time,
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, V: Versions> Committable
for VersionedVoteData<TYPES, DATA, V>
{
fn commit(&self) -> Commitment<Self> {
if self.version < V::Marketplace::VERSION {
let bytes: [u8; 32] = self.data.commit().into();
Commitment::<Self>::from_raw(bytes)
} else {
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 TimeoutData<TYPES> {
fn commit(&self) -> Commitment<Self> {
committable::RawCommitmentBuilder::new("Timeout data")
.u64(*self.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 Committable for VidData {
fn commit(&self) -> Commitment<Self> {
committable::RawCommitmentBuilder::new("VID data")
.var_size_bytes(self.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()
}
}
fn view_and_relay_commit<TYPES: NodeType, T: Committable>(
view: TYPES::Time,
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 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 ViewSyncCommitData<TYPES> {
fn commit(&self) -> Commitment<Self> {
view_and_relay_commit::<TYPES, Self>(self.round, self.relay, "View Sync Commit")
}
}
impl<V: sealed::Sealed + Committable + Clone + Serialize + Debug + PartialEq + Hash + Eq> Voteable
for V
{
}
pub type QuorumVote<TYPES> = SimpleVote<TYPES, QuorumData<TYPES>>;
pub type DaVote<TYPES> = SimpleVote<TYPES, DaData>;
pub type TimeoutVote<TYPES> = SimpleVote<TYPES, TimeoutData<TYPES>>;
pub type ViewSyncCommitVote<TYPES> = SimpleVote<TYPES, ViewSyncCommitData<TYPES>>;
pub type ViewSyncPreCommitVote<TYPES> = SimpleVote<TYPES, ViewSyncPreCommitData<TYPES>>;
pub type ViewSyncFinalizeVote<TYPES> = SimpleVote<TYPES, ViewSyncFinalizeData<TYPES>>;
pub type UpgradeVote<TYPES> = SimpleVote<TYPES, UpgradeProposalData<TYPES>>;