Skip to content

Commit efe3238

Browse files
samkim-cryptobw-solana
authored andcommitted
[votor] Replace VoteCertificate with either VoteCertificateBuilder or CertificateMessage (anza-xyz#304)
1 parent bda17a2 commit efe3238

File tree

3 files changed

+52
-64
lines changed

3 files changed

+52
-64
lines changed

votor/src/certificate_pool.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use {
44
certificate_pool::{
55
parent_ready_tracker::ParentReadyTracker,
66
stats::CertificatePoolStats,
7-
vote_certificate::{CertificateError, VoteCertificate},
7+
vote_certificate_builder::{CertificateError, VoteCertificateBuilder},
88
vote_pool::{DuplicateBlockVotePool, SimpleVotePool, VotePool, VotePoolType},
99
},
1010
conflicting_types,
@@ -37,7 +37,7 @@ use {
3737

3838
pub mod parent_ready_tracker;
3939
mod stats;
40-
mod vote_certificate;
40+
mod vote_certificate_builder;
4141
mod vote_pool;
4242

4343
impl VoteType {
@@ -233,16 +233,16 @@ impl CertificatePool {
233233
if accumulated_stake as f64 / (total_stake as f64) < limit {
234234
continue;
235235
}
236-
let mut vote_certificate = VoteCertificate::new(cert_id);
236+
let mut vote_certificate_builder = VoteCertificateBuilder::new(cert_id);
237237
vote_types.iter().for_each(|vote_type| {
238238
if let Some(vote_pool) = self.vote_pools.get(&(slot, *vote_type)) {
239239
match vote_pool {
240-
VotePoolType::SimpleVotePool(pool) => pool.add_to_certificate(&mut vote_certificate),
241-
VotePoolType::DuplicateBlockVotePool(pool) => pool.add_to_certificate(block_id.as_ref().expect("Duplicate block pool for {vote_type:?} expects a block id for certificate {cert_id:?}"), &mut vote_certificate),
240+
VotePoolType::SimpleVotePool(pool) => pool.add_to_certificate(&mut vote_certificate_builder),
241+
VotePoolType::DuplicateBlockVotePool(pool) => pool.add_to_certificate(block_id.as_ref().expect("Duplicate block pool for {vote_type:?} expects a block id for certificate {cert_id:?}"), &mut vote_certificate_builder),
242242
};
243243
}
244244
});
245-
let new_cert = Arc::new(vote_certificate.certificate());
245+
let new_cert = Arc::new(vote_certificate_builder.build());
246246
self.send_and_insert_certificate(cert_id, new_cert.clone(), events)?;
247247
self.stats
248248
.incr_cert_type(new_cert.certificate.certificate_type, true);

votor/src/certificate_pool/vote_certificate.rs renamed to votor/src/certificate_pool/vote_certificate_builder.rs

Lines changed: 37 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
use {
22
crate::CertificateId,
33
bitvec::prelude::*,
4-
solana_bls_signatures::{
5-
BlsError, Pubkey as BlsPubkey, PubkeyProjective, Signature, SignatureProjective,
6-
},
4+
solana_bls_signatures::{BlsError, Pubkey as BlsPubkey, PubkeyProjective, SignatureProjective},
75
solana_runtime::epoch_stakes::BLSPubkeyToRankMap,
86
solana_vote::alpenglow::{
97
bls_message::{CertificateMessage, VoteMessage},
@@ -29,70 +27,56 @@ pub enum CertificateError {
2927
ValidatorDoesNotExist(usize),
3028
}
3129

32-
//TODO(wen): Maybe we can merge all the below functions into CertificateMessage.
30+
/// A builder for creating a `CertificateMessage` by efficiently aggregating BLS signatures.
3331
#[derive(Clone)]
34-
pub struct VoteCertificate(CertificateMessage);
32+
pub struct VoteCertificateBuilder {
33+
certificate: Certificate,
34+
signature: SignatureProjective,
35+
bitmap: BitVec<u8, Lsb0>,
36+
}
3537

36-
impl From<CertificateMessage> for VoteCertificate {
37-
fn from(certificate_message: CertificateMessage) -> Self {
38-
Self(certificate_message)
38+
impl TryFrom<CertificateMessage> for VoteCertificateBuilder {
39+
type Error = CertificateError;
40+
41+
fn try_from(message: CertificateMessage) -> Result<Self, Self::Error> {
42+
let projective_signature = SignatureProjective::try_from(message.signature)?;
43+
Ok(VoteCertificateBuilder {
44+
certificate: message.certificate,
45+
signature: projective_signature,
46+
bitmap: message.bitmap,
47+
})
3948
}
4049
}
4150

42-
impl VoteCertificate {
51+
impl VoteCertificateBuilder {
4352
pub fn new(certificate_id: CertificateId) -> Self {
44-
VoteCertificate(CertificateMessage {
53+
Self {
4554
certificate: certificate_id.into(),
46-
signature: Signature::default(),
55+
signature: SignatureProjective::identity(),
4756
bitmap: BitVec::<u8, Lsb0>::repeat(false, MAXIMUM_VALIDATORS),
48-
})
57+
}
4958
}
5059

51-
pub fn aggregate<'a, 'b, T>(&mut self, messages: T)
52-
where
53-
T: Iterator<Item = &'a VoteMessage>,
54-
Self: 'b,
55-
'b: 'a,
56-
{
57-
let signature = &mut self.0.signature;
58-
// TODO: signature aggregation can be done out-of-order;
59-
// consider aggregating signatures separately in parallel
60-
let mut current_signature = if signature == &Signature::default() {
61-
SignatureProjective::identity()
62-
} else {
63-
SignatureProjective::try_from(*signature).expect("Invalid signature")
64-
};
65-
66-
// aggregate the votes
67-
let bitmap = &mut self.0.bitmap;
60+
/// Aggregates a slice of `VoteMessage`s into the builder.
61+
pub fn aggregate(&mut self, messages: &[VoteMessage]) -> Result<(), CertificateError> {
6862
for vote_message in messages {
69-
// set bit-vector for the validator
70-
//
71-
// TODO: This only accounts for one type of vote. Update this after
72-
// we have a base3 encoding implementation.
73-
assert!(
74-
bitmap.len() > vote_message.rank as usize,
75-
"Vote rank {} exceeds bitmap length {}",
76-
vote_message.rank,
77-
bitmap.len()
78-
);
79-
assert!(
80-
bitmap.get(vote_message.rank as usize).as_deref() != Some(&true),
81-
"Conflicting vote check should make this unreachable {vote_message:?}"
82-
);
83-
bitmap.set(vote_message.rank as usize, true);
84-
// aggregate the signature
85-
current_signature
86-
.aggregate_with([&vote_message.signature])
87-
.expect(
88-
"Failed to aggregate signature: {vote_message.signature:?} into {current_signature:?}"
89-
);
63+
if self.bitmap.len() <= vote_message.rank as usize {
64+
return Err(CertificateError::ValidatorDoesNotExist(
65+
vote_message.rank as usize,
66+
));
67+
}
68+
self.bitmap.set(vote_message.rank as usize, true);
9069
}
91-
*signature = Signature::from(current_signature);
70+
let signature_iter = messages.iter().map(|vote_message| &vote_message.signature);
71+
Ok(self.signature.aggregate_with(signature_iter)?)
9272
}
9373

94-
pub fn certificate(self) -> CertificateMessage {
95-
self.0
74+
pub fn build(self) -> CertificateMessage {
75+
CertificateMessage {
76+
certificate: self.certificate,
77+
signature: self.signature.into(),
78+
bitmap: self.bitmap,
79+
}
9680
}
9781
}
9882

votor/src/certificate_pool/vote_pool.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use {
2-
crate::{certificate_pool::vote_certificate::VoteCertificate, Stake},
2+
crate::{certificate_pool::vote_certificate_builder::VoteCertificateBuilder, Stake},
33
solana_pubkey::Pubkey,
44
solana_sdk::hash::Hash,
55
solana_vote::alpenglow::bls_message::VoteMessage,
@@ -96,8 +96,10 @@ impl SimpleVotePool {
9696
true
9797
}
9898

99-
pub fn add_to_certificate(&self, output: &mut VoteCertificate) {
100-
output.aggregate(self.vote_entry.transactions.iter())
99+
pub fn add_to_certificate(&self, output: &mut VoteCertificateBuilder) {
100+
output
101+
.aggregate(&self.vote_entry.transactions)
102+
.expect("Incoming vote message signatures are assumed to be valid")
101103
}
102104
}
103105

@@ -175,9 +177,11 @@ impl DuplicateBlockVotePool {
175177
.map_or(0, |vote_entries| vote_entries.total_stake_by_key)
176178
}
177179

178-
pub fn add_to_certificate(&self, block_id: &Hash, output: &mut VoteCertificate) {
180+
pub fn add_to_certificate(&self, block_id: &Hash, output: &mut VoteCertificateBuilder) {
179181
if let Some(vote_entries) = self.votes.get(block_id) {
180-
output.aggregate(vote_entries.transactions.iter())
182+
output
183+
.aggregate(&vote_entries.transactions)
184+
.expect("Incoming vote message signatures are assumed to be valid")
181185
}
182186
}
183187

0 commit comments

Comments
 (0)