Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ members = [
"vortexor",
"vote",
"votor",
"votor-messages",
"watchtower",
"wen-restart",
"xdp",
Expand Down Expand Up @@ -554,6 +555,7 @@ solana-version = { path = "version", version = "=3.1.0" }
solana-vote = { path = "vote", version = "=3.1.0" }
solana-vote-interface = "3.0.0"
solana-vote-program = { path = "programs/vote", version = "=3.1.0", default-features = false }
solana-votor-messages = { path = "votor-messages", version = "=3.1.0" }
solana-wen-restart = { path = "wen-restart", version = "=3.1.0" }
solana-zk-elgamal-proof-program = { path = "programs/zk-elgamal-proof", version = "=3.1.0" }
solana-zk-sdk = "4.0.0"
Expand Down
32 changes: 32 additions & 0 deletions votor-messages/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
[package]
name = "solana-votor-messages"
description = "Blockchain, Rebuilt for Scale"
documentation = "https://docs.rs/solana-votor-messages"
readme = "../README.md"
version = { workspace = true }
authors = { workspace = true }
repository = { workspace = true }
homepage = { workspace = true }
license = { workspace = true }
edition = { workspace = true }

[features]
frozen-abi = ["dep:solana-frozen-abi", "dep:solana-frozen-abi-macro"]

[dependencies]
serde = { workspace = true }
solana-bls-signatures = { workspace = true, features = [
"bytemuck", "solana-signer-derive",
] }
solana-clock = { workspace = true }
solana-frozen-abi = { workspace = true, optional = true, features = [
"frozen-abi",
] }
solana-frozen-abi-macro = { workspace = true, optional = true, features = [
"frozen-abi",
] }
solana-hash = { workspace = true, features = ["serde"] }
solana-logger = { workspace = true }

[lints]
workspace = true
193 changes: 193 additions & 0 deletions votor-messages/src/consensus_message.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
//! Put Alpenglow consensus messages here so all clients can agree on the format.
use {
crate::vote::Vote,
serde::{Deserialize, Serialize},
solana_bls_signatures::Signature as BLSSignature,
solana_clock::Slot,
solana_hash::Hash,
};

/// The seed used to derive the BLS keypair
pub const BLS_KEYPAIR_DERIVE_SEED: &[u8; 9] = b"alpenglow";

/// Block, a (slot, hash) tuple
pub type Block = (Slot, Hash);

#[cfg_attr(
feature = "frozen-abi",
derive(AbiExample),
frozen_abi(digest = "B6rf5Zh4zcGhKdxKVpW6An4Ns2yujVqGvAK6cM5YGFhP")
)]
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
/// BLS vote message, we need rank to look up pubkey
pub struct VoteMessage {
/// The vote
pub vote: Vote,
/// The signature
pub signature: BLSSignature,
/// The rank of the validator
pub rank: u16,
}

#[cfg_attr(
feature = "frozen-abi",
derive(AbiExample, AbiEnumVisitor),
frozen_abi(digest = "APmpbbqEiJtCrxgjSs8FuMNcM1Qyzc5HtMW7KR79DGcF")
)]
/// Certificate details
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize)]
pub enum Certificate {
/// Finalize certificate
Finalize(Slot),
/// Fast finalize certificate
FinalizeFast(Slot, Hash),
/// Notarize certificate
Notarize(Slot, Hash),
/// Notarize fallback certificate
NotarizeFallback(Slot, Hash),
/// Skip certificate
Skip(Slot),
}

#[cfg_attr(
feature = "frozen-abi",
derive(AbiExample, AbiEnumVisitor),
frozen_abi(digest = "3en2tmFekuD3SWbBnNPqeJSrxDeTJkKJe3CCimANrrpQ")
)]
/// Certificate type
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize)]
pub enum CertificateType {
/// Finalize certificate
Finalize,
/// Fast finalize certificate
FinalizeFast,
/// Notarize certificate
Notarize,
/// Notarize fallback certificate
NotarizeFallback,
/// Skip certificate
Skip,
}

impl Certificate {
/// Create a new certificate from a CertificateType, Slot, and Option<Hash>
pub fn new(certificate_type: CertificateType, slot: Slot, hash: Option<Hash>) -> Self {
match (certificate_type, hash) {
(CertificateType::Finalize, None) => Certificate::Finalize(slot),
(CertificateType::FinalizeFast, Some(hash)) => Certificate::FinalizeFast(slot, hash),
(CertificateType::Notarize, Some(hash)) => Certificate::Notarize(slot, hash),
(CertificateType::NotarizeFallback, Some(hash)) => {
Certificate::NotarizeFallback(slot, hash)
}
(CertificateType::Skip, None) => Certificate::Skip(slot),
_ => panic!("Invalid certificate type and hash combination"),
}
}

/// Get the certificate type
pub fn certificate_type(&self) -> CertificateType {
match self {
Certificate::Finalize(_) => CertificateType::Finalize,
Certificate::FinalizeFast(_, _) => CertificateType::FinalizeFast,
Certificate::Notarize(_, _) => CertificateType::Notarize,
Certificate::NotarizeFallback(_, _) => CertificateType::NotarizeFallback,
Certificate::Skip(_) => CertificateType::Skip,
}
}

/// Get the slot of the certificate
pub fn slot(&self) -> Slot {
match self {
Certificate::Finalize(slot)
| Certificate::FinalizeFast(slot, _)
| Certificate::Notarize(slot, _)
| Certificate::NotarizeFallback(slot, _)
| Certificate::Skip(slot) => *slot,
}
}

/// Is this a fast finalize certificate?
pub fn is_fast_finalization(&self) -> bool {
matches!(self, Self::FinalizeFast(_, _))
}

/// Is this a finalize / fast finalize certificate?
pub fn is_finalization(&self) -> bool {
matches!(self, Self::Finalize(_) | Self::FinalizeFast(_, _))
}

/// Is this a notarize fallback certificate?
pub fn is_notarize_fallback(&self) -> bool {
matches!(self, Self::NotarizeFallback(_, _))
}

/// Is this a skip certificate?
pub fn is_skip(&self) -> bool {
matches!(self, Self::Skip(_))
}

/// Gets the block associated with this certificate, if present
pub fn to_block(self) -> Option<Block> {
match self {
Certificate::Finalize(_) | Certificate::Skip(_) => None,
Certificate::Notarize(slot, block_id)
| Certificate::NotarizeFallback(slot, block_id)
| Certificate::FinalizeFast(slot, block_id) => Some((slot, block_id)),
}
}
}

#[cfg_attr(
feature = "frozen-abi",
derive(AbiExample),
frozen_abi(digest = "2mt3bVxZBf2QzS7uZknbgP7kun4eEfzjpbW7QwXqz6Qo")
)]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
/// BLS vote message, we need rank to look up pubkey
pub struct CertificateMessage {
/// The certificate
pub certificate: Certificate,
/// The signature
pub signature: BLSSignature,
/// The bitmap for validators, see solana-signer-store for encoding format
pub bitmap: Vec<u8>,
}

#[cfg_attr(
feature = "frozen-abi",
derive(AbiExample, AbiEnumVisitor),
frozen_abi(digest = "CwKtX5nWfGbQZSBh1YTr3NABwThE4zFTxzQL9K5xkqYW")
)]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[allow(clippy::large_enum_variant)]
/// BLS message data in Alpenglow
pub enum ConsensusMessage {
/// Vote message, with the vote and the rank of the validator.
Vote(VoteMessage),
/// Certificate message
Certificate(CertificateMessage),
}

impl ConsensusMessage {
/// Create a new vote message
pub fn new_vote(vote: Vote, signature: BLSSignature, rank: u16) -> Self {
Self::Vote(VoteMessage {
vote,
signature,
rank,
})
}

/// Create a new certificate message
pub fn new_certificate(
certificate: Certificate,
bitmap: Vec<u8>,
signature: BLSSignature,
) -> Self {
Self::Certificate(CertificateMessage {
certificate,
signature,
bitmap,
})
}
}
10 changes: 10 additions & 0 deletions votor-messages/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
//! Alpenglow vote message types
#![cfg_attr(feature = "frozen-abi", feature(min_specialization))]
#![deny(missing_docs)]

pub mod consensus_message;
pub mod vote;

#[cfg_attr(feature = "frozen-abi", macro_use)]
#[cfg(feature = "frozen-abi")]
extern crate solana_frozen_abi_macro;
Loading
Loading