commonware_consensus/simplex/
types.rs

1//! Types used in [crate::simplex].
2
3use crate::{
4    simplex::signing_scheme::Scheme,
5    types::{Epoch, Round, View},
6    Epochable, Viewable,
7};
8use bytes::{Buf, BufMut};
9use commonware_codec::{varint::UInt, EncodeSize, Error, Read, ReadExt, ReadRangeExt, Write};
10use commonware_cryptography::{Digest, PublicKey};
11use commonware_utils::{max_faults, quorum, set::Ordered};
12use rand::{CryptoRng, Rng};
13use std::{collections::HashSet, fmt::Debug, hash::Hash};
14
15/// Context is a collection of metadata from consensus about a given payload.
16/// It provides information about the current epoch/view and the parent payload that new proposals are built on.
17#[derive(Clone)]
18pub struct Context<D: Digest, P: PublicKey> {
19    /// Current round of consensus.
20    pub round: Round,
21    /// Leader of the current round.
22    pub leader: P,
23    /// Parent the payload is built on.
24    ///
25    /// If there is a gap between the current view and the parent view, the participant
26    /// must possess a nullification for each discarded view to safely vote on the proposed
27    /// payload (any view without a nullification may eventually be finalized and skipping
28    /// it would result in a fork).
29    pub parent: (View, D),
30}
31
32impl<D: Digest, P: PublicKey> Epochable for Context<D, P> {
33    type Epoch = Epoch;
34
35    fn epoch(&self) -> Epoch {
36        self.round.epoch()
37    }
38}
39
40impl<D: Digest, P: PublicKey> Viewable for Context<D, P> {
41    type View = View;
42
43    fn view(&self) -> View {
44        self.round.view()
45    }
46}
47
48/// Attributable is a trait that provides access to the signer index.
49/// This is used to identify which participant signed a given message.
50pub trait Attributable {
51    /// Returns the index of the signer (validator) who produced this message.
52    fn signer(&self) -> u32;
53}
54
55/// AttributableVec is a vector of [Attributable] items where a given [Attributable::signer()]
56/// can add at most one item.
57pub struct AttributableVec<T: Attributable> {
58    data: Vec<Option<T>>,
59    added: usize,
60}
61
62impl<T: Attributable> AttributableVec<T> {
63    /// Creates a new [AttributableVec] with the given number of participants.
64    pub fn new(participants: usize) -> Self {
65        // `resize_with` avoids requiring `T: Clone` while pre-filling with `None`.
66        let mut data = Vec::with_capacity(participants);
67        data.resize_with(participants, || None);
68
69        Self { data, added: 0 }
70    }
71
72    /// Adds an item to the [AttributableVec] if it has not been added yet.
73    ///
74    /// Returns `true` if the item was added, `false` if it was already added.
75    pub fn push(&mut self, item: T) -> bool {
76        let index = item.signer() as usize;
77        if self.data[index].is_some() {
78            return false;
79        }
80        self.data[index] = Some(item);
81        self.added += 1;
82        true
83    }
84
85    /// Returns the number of items in the [AttributableVec].
86    pub fn len(&self) -> usize {
87        self.added
88    }
89
90    /// Returns `true` if the [AttributableVec] is empty.
91    pub fn is_empty(&self) -> bool {
92        self.added == 0
93    }
94
95    /// Returns an ordered iterator over [Attributable::signer()]s in the [AttributableVec].
96    pub fn iter(&self) -> impl Iterator<Item = &T> {
97        self.data.iter().filter_map(|o| o.as_ref())
98    }
99}
100
101/// Identifies the signing domain for a vote or certificate.
102///
103/// Implementations use the context to derive domain-separated message bytes for both
104/// individual votes and recovered certificates.
105#[derive(Copy, Clone)]
106pub enum VoteContext<'a, D: Digest> {
107    /// Signing context for notarize votes and certificates, carrying the proposal.
108    Notarize { proposal: &'a Proposal<D> },
109    /// Signing context for nullify votes and certificates, scoped to a round.
110    Nullify { round: Round },
111    /// Signing context for finalize votes and certificates, carrying the proposal.
112    Finalize { proposal: &'a Proposal<D> },
113}
114
115impl<D: Digest> Viewable for VoteContext<'_, D> {
116    type View = View;
117
118    fn view(&self) -> View {
119        match self {
120            VoteContext::Notarize { proposal } => proposal.view(),
121            VoteContext::Nullify { round } => round.view(),
122            VoteContext::Finalize { proposal } => proposal.view(),
123        }
124    }
125}
126
127/// Signed vote emitted by a participant.
128#[derive(Clone, Debug)]
129pub struct Vote<S: Scheme> {
130    /// Index of the signer inside the participant set.
131    pub signer: u32,
132    /// Scheme-specific signature or share produced for the vote context.
133    pub signature: S::Signature,
134}
135
136impl<S: Scheme> PartialEq for Vote<S> {
137    fn eq(&self, other: &Self) -> bool {
138        self.signer == other.signer && self.signature == other.signature
139    }
140}
141
142impl<S: Scheme> Eq for Vote<S> {}
143
144impl<S: Scheme> Hash for Vote<S> {
145    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
146        self.signer.hash(state);
147        self.signature.hash(state);
148    }
149}
150
151impl<S: Scheme> Write for Vote<S> {
152    fn write(&self, writer: &mut impl BufMut) {
153        self.signer.write(writer);
154        self.signature.write(writer);
155    }
156}
157
158impl<S: Scheme> EncodeSize for Vote<S> {
159    fn encode_size(&self) -> usize {
160        self.signer.encode_size() + self.signature.encode_size()
161    }
162}
163
164impl<S: Scheme> Read for Vote<S> {
165    type Cfg = ();
166
167    fn read_cfg(reader: &mut impl Buf, _: &()) -> Result<Self, Error> {
168        let signer = u32::read(reader)?;
169        let signature = S::Signature::read(reader)?;
170
171        Ok(Self { signer, signature })
172    }
173}
174
175/// Result of verifying a batch of votes.
176pub struct VoteVerification<S: Scheme> {
177    /// Contains the votes accepted by the scheme.
178    pub verified: Vec<Vote<S>>,
179    /// Identifies the participant indices rejected during batch verification.
180    pub invalid_signers: Vec<u32>,
181}
182
183impl<S: Scheme> VoteVerification<S> {
184    /// Creates a new `VoteVerification` result.
185    pub fn new(verified: Vec<Vote<S>>, invalid_signers: Vec<u32>) -> Self {
186        Self {
187            verified,
188            invalid_signers,
189        }
190    }
191}
192
193/// Extension trait for `Ordered` participant sets providing quorum and index utilities.
194pub trait OrderedExt<P> {
195    /// Returns the quorum value (2f+1) for this participant set.
196    fn quorum(&self) -> u32;
197
198    /// Returns the maximum number of faults (f) tolerated by this participant set.
199    fn max_faults(&self) -> u32;
200
201    /// Returns the participant key at the given index.
202    fn key(&self, index: u32) -> Option<&P>;
203
204    /// Returns the index for the given participant key, if present.
205    fn index(&self, key: &P) -> Option<u32>;
206}
207
208impl<P: PublicKey> OrderedExt<P> for Ordered<P> {
209    fn quorum(&self) -> u32 {
210        quorum(self.len() as u32)
211    }
212
213    fn max_faults(&self) -> u32 {
214        max_faults(self.len() as u32)
215    }
216
217    fn index(&self, key: &P) -> Option<u32> {
218        self.position(key).map(|index| index as u32)
219    }
220
221    fn key(&self, index: u32) -> Option<&P> {
222        self.get(index as usize)
223    }
224}
225
226/// `BatchVerifier` is a utility for tracking and batch verifying consensus messages.
227///
228/// In consensus, verifying multiple signatures at the same time can be much more efficient
229/// than verifying them one by one. This struct collects messages from participants in consensus
230/// and signals they are ready to be verified when certain conditions are met (e.g., enough messages
231/// to potentially reach a quorum, or when a leader's message is received).
232///
233/// To avoid unnecessary verification, it also tracks the number of already verified messages (ensuring
234/// we no longer attempt to verify messages after a quorum of valid messages have already been verified).
235pub struct BatchVerifier<S: Scheme, D: Digest> {
236    /// Signing scheme used to verify votes and assemble certificates.
237    scheme: S,
238
239    /// Required quorum size. `None` disables quorum-based readiness.
240    quorum: Option<usize>,
241
242    /// Current leader index.
243    leader: Option<u32>,
244    /// Proposal associated with the current leader.
245    leader_proposal: Option<Proposal<D>>,
246
247    /// Pending notarize votes waiting to be verified.
248    notarizes: Vec<Notarize<S, D>>,
249    /// Forces notarize verification as soon as possible (set when the leader proposal is known).
250    notarizes_force: bool,
251    /// Count of already-verified notarize votes.
252    notarizes_verified: usize,
253
254    /// Pending nullify votes waiting to be verified.
255    nullifies: Vec<Nullify<S>>,
256    /// Count of already-verified nullify votes.
257    nullifies_verified: usize,
258
259    /// Pending finalize votes waiting to be verified.
260    finalizes: Vec<Finalize<S, D>>,
261    /// Count of already-verified finalize votes.
262    finalizes_verified: usize,
263}
264
265impl<S: Scheme, D: Digest> BatchVerifier<S, D> {
266    /// Creates a new `BatchVerifier`.
267    ///
268    /// # Arguments
269    ///
270    /// * `signing` - Scheme handle used to verify and aggregate votes.
271    /// * `quorum` - An optional `u32` specifying the number of votes (2f+1)
272    ///   required to reach a quorum. If `None`, batch verification readiness
273    ///   checks based on quorum size are skipped.
274    pub fn new(scheme: S, quorum: Option<u32>) -> Self {
275        Self {
276            scheme,
277
278            // Store quorum as usize to simplify comparisons against queue lengths.
279            quorum: quorum.map(|q| q as usize),
280
281            leader: None,
282            leader_proposal: None,
283
284            notarizes: Vec::new(),
285            notarizes_force: false,
286            notarizes_verified: 0,
287
288            nullifies: Vec::new(),
289            nullifies_verified: 0,
290
291            finalizes: Vec::new(),
292            finalizes_verified: 0,
293        }
294    }
295
296    /// Clears any pending messages that are not for the leader's proposal and forces
297    /// the notarizes to be verified.
298    ///
299    /// We force verification because we need to know the leader's proposal
300    /// to begin verifying it.
301    fn set_leader_proposal(&mut self, proposal: Proposal<D>) {
302        // Drop all notarizes/finalizes that aren't for the leader proposal
303        self.notarizes.retain(|n| n.proposal == proposal);
304        self.finalizes.retain(|f| f.proposal == proposal);
305
306        // Set the leader proposal
307        self.leader_proposal = Some(proposal);
308
309        // Force the notarizes to be verified
310        self.notarizes_force = true;
311    }
312
313    /// Adds a [Voter] message to the batch for later verification.
314    ///
315    /// If the message has already been verified (e.g., we built it), it increments
316    /// the count of verified messages directly. Otherwise, it adds the message to
317    /// the appropriate pending queue.
318    ///
319    /// If a leader is known and the message is a [Voter::Notarize] from that leader,
320    /// this method may trigger `set_leader_proposal`.
321    ///
322    /// Recovered messages (e.g., [Voter::Notarization], [Voter::Nullification], [Voter::Finalization])
323    /// are not expected here and will cause a panic.
324    ///
325    /// # Arguments
326    ///
327    /// * `msg` - The [Voter] message to add.
328    /// * `verified` - A boolean indicating if the message has already been verified.
329    pub fn add(&mut self, msg: Voter<S, D>, verified: bool) {
330        match msg {
331            Voter::Notarize(notarize) => {
332                if let Some(ref leader_proposal) = self.leader_proposal {
333                    // If leader proposal is set and the message is not for it, drop it
334                    if leader_proposal != &notarize.proposal {
335                        return;
336                    }
337                } else if let Some(leader) = self.leader {
338                    // If leader is set but leader proposal is not, set it
339                    if leader == notarize.signer() {
340                        // Set the leader proposal
341                        self.set_leader_proposal(notarize.proposal.clone());
342                    }
343                }
344
345                // If we've made it this far, add the notarize
346                if verified {
347                    self.notarizes_verified += 1;
348                } else {
349                    self.notarizes.push(notarize);
350                }
351            }
352            Voter::Nullify(nullify) => {
353                if verified {
354                    self.nullifies_verified += 1;
355                } else {
356                    self.nullifies.push(nullify);
357                }
358            }
359            Voter::Finalize(finalize) => {
360                // If leader proposal is set and the message is not for it, drop it
361                if let Some(ref leader_proposal) = self.leader_proposal {
362                    if leader_proposal != &finalize.proposal {
363                        return;
364                    }
365                }
366
367                // If we've made it this far, add the finalize
368                if verified {
369                    self.finalizes_verified += 1;
370                } else {
371                    self.finalizes.push(finalize);
372                }
373            }
374            Voter::Notarization(_) | Voter::Nullification(_) | Voter::Finalization(_) => {
375                unreachable!("should not be adding recovered messages to partial verifier");
376            }
377        }
378    }
379
380    /// Sets the leader for the current consensus view.
381    ///
382    /// If the leader is found, we may call `set_leader_proposal` to clear any pending
383    /// messages that are not for the leader's proposal and to force verification of said
384    /// proposal.
385    ///
386    /// # Arguments
387    ///
388    /// * `leader` - The `u32` identifier of the leader.
389    pub fn set_leader(&mut self, leader: u32) {
390        // Set the leader
391        assert!(self.leader.is_none());
392        self.leader = Some(leader);
393
394        // Look for a notarize from the leader
395        let Some(notarize) = self.notarizes.iter().find(|n| n.signer() == leader) else {
396            return;
397        };
398
399        // Set the leader proposal
400        self.set_leader_proposal(notarize.proposal.clone());
401    }
402
403    /// Verifies a batch of pending [Voter::Notarize] messages.
404    ///
405    /// It uses `S::verify_votes` for efficient batch verification.
406    ///
407    /// # Arguments
408    ///
409    /// * `rng` - Randomness source used by schemes that require batching randomness.
410    /// * `namespace` - The namespace for signature domain separation.
411    ///
412    /// # Returns
413    ///
414    /// A tuple containing:
415    /// * A `Vec<Voter<S, D>>` of successfully verified [Voter::Notarize] messages (wrapped as [Voter]).
416    /// * A `Vec<u32>` of signer indices for whom verification failed.
417    pub fn verify_notarizes<R: Rng + CryptoRng>(
418        &mut self,
419        rng: &mut R,
420        namespace: &[u8],
421    ) -> (Vec<Voter<S, D>>, Vec<u32>) {
422        self.notarizes_force = false;
423
424        let notarizes = std::mem::take(&mut self.notarizes);
425
426        // Early return if there are no notarizes to verify
427        if notarizes.is_empty() {
428            return (vec![], vec![]);
429        }
430
431        let (proposals, votes): (Vec<_>, Vec<_>) =
432            notarizes.into_iter().map(|n| (n.proposal, n.vote)).unzip();
433
434        let proposal = &proposals[0];
435
436        let VoteVerification {
437            verified,
438            invalid_signers,
439        } = self
440            .scheme
441            .verify_votes(rng, namespace, VoteContext::Notarize { proposal }, votes);
442
443        self.notarizes_verified += verified.len();
444
445        (
446            verified
447                .into_iter()
448                .zip(proposals)
449                .map(|(vote, proposal)| Voter::Notarize(Notarize { proposal, vote }))
450                .collect(),
451            invalid_signers,
452        )
453    }
454
455    /// Checks if there are [Voter::Notarize] messages ready for batch verification.
456    ///
457    /// Verification is considered "ready" if:
458    /// 1. `notarizes_force` is true (e.g., after a leader's proposal is set).
459    /// 2. A leader and their proposal are known, and:
460    ///    a. The quorum (if set) has not yet been met by verified messages.
461    ///    b. The sum of verified and pending messages is enough to potentially reach the quorum.
462    /// 3. There are pending [Voter::Notarize] messages to verify.
463    ///
464    /// # Returns
465    ///
466    /// `true` if [Voter::Notarize] messages should be verified, `false` otherwise.
467    pub fn ready_notarizes(&self) -> bool {
468        // If there are no pending notarizes, there is nothing to do.
469        if self.notarizes.is_empty() {
470            return false;
471        }
472
473        // If we have the leader's notarize, we should verify immediately to start
474        // block verification.
475        if self.notarizes_force {
476            return true;
477        }
478
479        // If we don't yet know the leader, notarizes may contain messages for
480        // a number of different proposals.
481        if self.leader.is_none() || self.leader_proposal.is_none() {
482            return false;
483        }
484
485        // If we have a quorum, we need to check if we have enough verified and pending
486        if let Some(quorum) = self.quorum {
487            // If we have already performed sufficient verifications, there is nothing more
488            // to do.
489            if self.notarizes_verified >= quorum {
490                return false;
491            }
492
493            // If we don't have enough to reach the quorum, there is nothing to do yet.
494            if self.notarizes_verified + self.notarizes.len() < quorum {
495                return false;
496            }
497        }
498
499        // If there is no required quorum and we have pending notarizes, we should verify.
500        true
501    }
502
503    /// Verifies a batch of pending [Voter::Nullify] messages.
504    ///
505    /// It uses `S::verify_votes` for efficient batch verification.
506    ///
507    /// # Arguments
508    ///
509    /// * `rng` - Randomness source used by schemes that require batching randomness.
510    /// * `namespace` - The namespace for signature domain separation.
511    ///
512    /// # Returns
513    ///
514    /// A tuple containing:
515    /// * A `Vec<Voter<S, D>>` of successfully verified [Voter::Nullify] messages (wrapped as [Voter]).
516    /// * A `Vec<u32>` of signer indices for whom verification failed.
517    pub fn verify_nullifies<R: Rng + CryptoRng>(
518        &mut self,
519        rng: &mut R,
520        namespace: &[u8],
521    ) -> (Vec<Voter<S, D>>, Vec<u32>) {
522        let nullifies = std::mem::take(&mut self.nullifies);
523
524        // Early return if there are no nullifies to verify
525        if nullifies.is_empty() {
526            return (vec![], vec![]);
527        }
528
529        let round = nullifies[0].round;
530
531        let VoteVerification {
532            verified,
533            invalid_signers,
534        } = self.scheme.verify_votes::<_, D, _>(
535            rng,
536            namespace,
537            VoteContext::Nullify { round },
538            nullifies.into_iter().map(|nullify| nullify.vote),
539        );
540
541        self.nullifies_verified += verified.len();
542
543        (
544            verified
545                .into_iter()
546                .map(|vote| Voter::Nullify(Nullify { round, vote }))
547                .collect(),
548            invalid_signers,
549        )
550    }
551
552    /// Checks if there are [Voter::Nullify] messages ready for batch verification.
553    ///
554    /// Verification is considered "ready" if:
555    /// 1. The quorum (if set) has not yet been met by verified messages.
556    /// 2. The sum of verified and pending messages is enough to potentially reach the quorum.
557    /// 3. There are pending [Voter::Nullify] messages to verify.
558    ///
559    /// # Returns
560    ///
561    /// `true` if [Voter::Nullify] messages should be verified, `false` otherwise.
562    pub fn ready_nullifies(&self) -> bool {
563        // If there are no pending nullifies, there is nothing to do.
564        if self.nullifies.is_empty() {
565            return false;
566        }
567
568        if let Some(quorum) = self.quorum {
569            // If we have already performed sufficient verifications, there is nothing more
570            // to do.
571            if self.nullifies_verified >= quorum {
572                return false;
573            }
574
575            // If we don't have enough to reach the quorum, there is nothing to do yet.
576            if self.nullifies_verified + self.nullifies.len() < quorum {
577                return false;
578            }
579        }
580
581        // If there is no required quorum and we have pending nullifies, we should verify.
582        true
583    }
584
585    /// Verifies a batch of pending [Voter::Finalize] messages.
586    ///
587    /// It uses `S::verify_votes` for efficient batch verification.
588    ///
589    /// # Arguments
590    ///
591    /// * `rng` - Randomness source used by schemes that require batching randomness.
592    /// * `namespace` - The namespace for signature domain separation.
593    ///
594    /// # Returns
595    ///
596    /// A tuple containing:
597    /// * A `Vec<Voter<S, D>>` of successfully verified [Voter::Finalize] messages (wrapped as [Voter]).
598    /// * A `Vec<u32>` of signer indices for whom verification failed.
599    pub fn verify_finalizes<R: Rng + CryptoRng>(
600        &mut self,
601        rng: &mut R,
602        namespace: &[u8],
603    ) -> (Vec<Voter<S, D>>, Vec<u32>) {
604        let finalizes = std::mem::take(&mut self.finalizes);
605
606        // Early return if there are no finalizes to verify
607        if finalizes.is_empty() {
608            return (vec![], vec![]);
609        }
610
611        let (proposals, votes): (Vec<_>, Vec<_>) =
612            finalizes.into_iter().map(|n| (n.proposal, n.vote)).unzip();
613
614        let proposal = &proposals[0];
615
616        let VoteVerification {
617            verified,
618            invalid_signers,
619        } = self
620            .scheme
621            .verify_votes(rng, namespace, VoteContext::Finalize { proposal }, votes);
622
623        self.finalizes_verified += verified.len();
624
625        (
626            verified
627                .into_iter()
628                .zip(proposals)
629                .map(|(vote, proposal)| Voter::Finalize(Finalize { proposal, vote }))
630                .collect(),
631            invalid_signers,
632        )
633    }
634
635    /// Checks if there are [Voter::Finalize] messages ready for batch verification.
636    ///
637    /// Verification is considered "ready" if:
638    /// 1. A leader and their proposal are known (finalizes are proposal-specific).
639    /// 2. The quorum (if set) has not yet been met by verified messages.
640    /// 3. The sum of verified and pending messages is enough to potentially reach the quorum.
641    /// 4. There are pending [Voter::Finalize] messages to verify.
642    ///
643    /// # Returns
644    ///
645    /// `true` if [Voter::Finalize] messages should be verified, `false` otherwise.
646    pub fn ready_finalizes(&self) -> bool {
647        // If there are no pending finalizes, there is nothing to do.
648        if self.finalizes.is_empty() {
649            return false;
650        }
651
652        // If we don't yet know the leader, finalizers may contain messages for
653        // a number of different proposals.
654        if self.leader.is_none() || self.leader_proposal.is_none() {
655            return false;
656        }
657        if let Some(quorum) = self.quorum {
658            // If we have already performed sufficient verifications, there is nothing more
659            // to do.
660            if self.finalizes_verified >= quorum {
661                return false;
662            }
663
664            // If we don't have enough to reach the quorum, there is nothing to do yet.
665            if self.finalizes_verified + self.finalizes.len() < quorum {
666                return false;
667            }
668        }
669
670        // If there is no required quorum and we have pending finalizes, we should verify.
671        true
672    }
673}
674
675/// Voter represents all possible message types that can be sent by validators
676/// in the consensus protocol.
677#[derive(Clone, Debug, PartialEq)]
678pub enum Voter<S: Scheme, D: Digest> {
679    /// A validator's notarize vote over a proposal
680    Notarize(Notarize<S, D>),
681    /// A recovered certificate for a notarization (scheme-specific)
682    Notarization(Notarization<S, D>),
683    /// A validator's nullify vote used to skip the current view (usually when the leader is unresponsive)
684    Nullify(Nullify<S>),
685    /// A recovered certificate for a nullification (scheme-specific)
686    Nullification(Nullification<S>),
687    /// A validator's finalize vote over a proposal
688    Finalize(Finalize<S, D>),
689    /// A recovered certificate for a finalization (scheme-specific)
690    Finalization(Finalization<S, D>),
691}
692
693impl<S: Scheme, D: Digest> Write for Voter<S, D> {
694    fn write(&self, writer: &mut impl BufMut) {
695        match self {
696            Voter::Notarize(v) => {
697                0u8.write(writer);
698                v.write(writer);
699            }
700            Voter::Notarization(v) => {
701                1u8.write(writer);
702                v.write(writer);
703            }
704            Voter::Nullify(v) => {
705                2u8.write(writer);
706                v.write(writer);
707            }
708            Voter::Nullification(v) => {
709                3u8.write(writer);
710                v.write(writer);
711            }
712            Voter::Finalize(v) => {
713                4u8.write(writer);
714                v.write(writer);
715            }
716            Voter::Finalization(v) => {
717                5u8.write(writer);
718                v.write(writer);
719            }
720        }
721    }
722}
723
724impl<S: Scheme, D: Digest> EncodeSize for Voter<S, D> {
725    fn encode_size(&self) -> usize {
726        1 + match self {
727            Voter::Notarize(v) => v.encode_size(),
728            Voter::Notarization(v) => v.encode_size(),
729            Voter::Nullify(v) => v.encode_size(),
730            Voter::Nullification(v) => v.encode_size(),
731            Voter::Finalize(v) => v.encode_size(),
732            Voter::Finalization(v) => v.encode_size(),
733        }
734    }
735}
736
737impl<S: Scheme, D: Digest> Read for Voter<S, D> {
738    type Cfg = <S::Certificate as Read>::Cfg;
739
740    fn read_cfg(reader: &mut impl Buf, cfg: &Self::Cfg) -> Result<Self, Error> {
741        let tag = <u8>::read(reader)?;
742        match tag {
743            0 => {
744                let v = Notarize::read(reader)?;
745                Ok(Voter::Notarize(v))
746            }
747            1 => {
748                let v = Notarization::read_cfg(reader, cfg)?;
749                Ok(Voter::Notarization(v))
750            }
751            2 => {
752                let v = Nullify::read(reader)?;
753                Ok(Voter::Nullify(v))
754            }
755            3 => {
756                let v = Nullification::read_cfg(reader, cfg)?;
757                Ok(Voter::Nullification(v))
758            }
759            4 => {
760                let v = Finalize::read(reader)?;
761                Ok(Voter::Finalize(v))
762            }
763            5 => {
764                let v = Finalization::read_cfg(reader, cfg)?;
765                Ok(Voter::Finalization(v))
766            }
767            _ => Err(Error::Invalid("consensus::simplex::Voter", "Invalid type")),
768        }
769    }
770}
771
772impl<S: Scheme, D: Digest> Epochable for Voter<S, D> {
773    type Epoch = Epoch;
774
775    fn epoch(&self) -> Epoch {
776        match self {
777            Voter::Notarize(v) => v.epoch(),
778            Voter::Notarization(v) => v.epoch(),
779            Voter::Nullify(v) => v.epoch(),
780            Voter::Nullification(v) => v.epoch(),
781            Voter::Finalize(v) => v.epoch(),
782            Voter::Finalization(v) => v.epoch(),
783        }
784    }
785}
786
787impl<S: Scheme, D: Digest> Viewable for Voter<S, D> {
788    type View = View;
789
790    fn view(&self) -> View {
791        match self {
792            Voter::Notarize(v) => v.view(),
793            Voter::Notarization(v) => v.view(),
794            Voter::Nullify(v) => v.view(),
795            Voter::Nullification(v) => v.view(),
796            Voter::Finalize(v) => v.view(),
797            Voter::Finalization(v) => v.view(),
798        }
799    }
800}
801
802/// Proposal represents a proposed block in the protocol.
803/// It includes the view number, the parent view, and the actual payload (typically a digest of block data).
804#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
805pub struct Proposal<D: Digest> {
806    /// The round in which this proposal is made
807    pub round: Round,
808    /// The view of the parent proposal that this one builds upon
809    pub parent: View,
810    /// The actual payload/content of the proposal (typically a digest of the block data)
811    pub payload: D,
812}
813
814impl<D: Digest> Proposal<D> {
815    /// Creates a new proposal with the specified view, parent view, and payload.
816    pub fn new(round: Round, parent: View, payload: D) -> Self {
817        Proposal {
818            round,
819            parent,
820            payload,
821        }
822    }
823}
824
825impl<D: Digest> Write for Proposal<D> {
826    fn write(&self, writer: &mut impl BufMut) {
827        self.round.write(writer);
828        UInt(self.parent).write(writer);
829        self.payload.write(writer)
830    }
831}
832
833impl<D: Digest> Read for Proposal<D> {
834    type Cfg = ();
835
836    fn read_cfg(reader: &mut impl Buf, _: &()) -> Result<Self, Error> {
837        let round = Round::read(reader)?;
838        let parent = UInt::read(reader)?.into();
839        let payload = D::read(reader)?;
840        Ok(Self {
841            round,
842            parent,
843            payload,
844        })
845    }
846}
847
848impl<D: Digest> EncodeSize for Proposal<D> {
849    fn encode_size(&self) -> usize {
850        self.round.encode_size() + UInt(self.parent).encode_size() + self.payload.encode_size()
851    }
852}
853
854impl<D: Digest> Epochable for Proposal<D> {
855    type Epoch = Epoch;
856
857    fn epoch(&self) -> Epoch {
858        self.round.epoch()
859    }
860}
861
862impl<D: Digest> Viewable for Proposal<D> {
863    type View = View;
864
865    fn view(&self) -> View {
866        self.round.view()
867    }
868}
869
870/// Validator vote that endorses a proposal for notarization.
871#[derive(Clone, Debug)]
872pub struct Notarize<S: Scheme, D: Digest> {
873    /// Proposal being notarized.
874    pub proposal: Proposal<D>,
875    /// Scheme-specific vote material.
876    pub vote: Vote<S>,
877}
878
879impl<S: Scheme, D: Digest> Notarize<S, D> {
880    /// Returns the round associated with this notarize vote.
881    pub fn round(&self) -> Round {
882        self.proposal.round
883    }
884}
885
886impl<S: Scheme, D: Digest> PartialEq for Notarize<S, D> {
887    fn eq(&self, other: &Self) -> bool {
888        self.proposal == other.proposal && self.vote == other.vote
889    }
890}
891
892impl<S: Scheme, D: Digest> Eq for Notarize<S, D> {}
893
894impl<S: Scheme, D: Digest> Hash for Notarize<S, D> {
895    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
896        self.proposal.hash(state);
897        self.vote.hash(state);
898    }
899}
900
901impl<S: Scheme, D: Digest> Notarize<S, D> {
902    /// Signs a notarize vote for the provided proposal.
903    pub fn sign(scheme: &S, namespace: &[u8], proposal: Proposal<D>) -> Option<Self> {
904        let vote = scheme.sign_vote(
905            namespace,
906            VoteContext::Notarize {
907                proposal: &proposal,
908            },
909        )?;
910
911        Some(Self { proposal, vote })
912    }
913
914    /// Verifies the notarize vote against the provided signing scheme.
915    ///
916    /// This ensures that the notarize signature is valid for the claimed proposal.
917    pub fn verify(&self, scheme: &S, namespace: &[u8]) -> bool {
918        scheme.verify_vote(
919            namespace,
920            VoteContext::Notarize {
921                proposal: &self.proposal,
922            },
923            &self.vote,
924        )
925    }
926}
927
928impl<S: Scheme, D: Digest> Write for Notarize<S, D> {
929    fn write(&self, writer: &mut impl BufMut) {
930        self.proposal.write(writer);
931        self.vote.write(writer);
932    }
933}
934
935impl<S: Scheme, D: Digest> EncodeSize for Notarize<S, D> {
936    fn encode_size(&self) -> usize {
937        self.proposal.encode_size() + self.vote.encode_size()
938    }
939}
940
941impl<S: Scheme, D: Digest> Read for Notarize<S, D> {
942    type Cfg = ();
943
944    fn read_cfg(reader: &mut impl Buf, _: &()) -> Result<Self, Error> {
945        let proposal = Proposal::read(reader)?;
946        let vote = Vote::read(reader)?;
947
948        Ok(Self { proposal, vote })
949    }
950}
951
952impl<S: Scheme, D: Digest> Attributable for Notarize<S, D> {
953    fn signer(&self) -> u32 {
954        self.vote.signer
955    }
956}
957
958impl<S: Scheme, D: Digest> Epochable for Notarize<S, D> {
959    type Epoch = Epoch;
960
961    fn epoch(&self) -> Epoch {
962        self.proposal.epoch()
963    }
964}
965
966impl<S: Scheme, D: Digest> Viewable for Notarize<S, D> {
967    type View = View;
968
969    fn view(&self) -> View {
970        self.proposal.view()
971    }
972}
973
974/// Aggregated notarization certificate recovered from notarize votes.
975/// When a proposal is notarized, it means at least 2f+1 validators have voted for it.
976///
977/// Some signing schemes embed an additional randomness seed in the certificate (used for
978/// leader rotation), it can be accessed via [`Scheme::seed`].
979#[derive(Clone, Debug)]
980pub struct Notarization<S: Scheme, D: Digest> {
981    /// The proposal that has been notarized.
982    pub proposal: Proposal<D>,
983    /// The recovered certificate for the proposal.
984    pub certificate: S::Certificate,
985}
986
987impl<S: Scheme, D: Digest> Notarization<S, D> {
988    /// Builds a notarization certificate from notarize votes for the same proposal.
989    pub fn from_notarizes<'a>(
990        scheme: &S,
991        notarizes: impl IntoIterator<Item = &'a Notarize<S, D>>,
992    ) -> Option<Self> {
993        let mut iter = notarizes.into_iter().peekable();
994        let proposal = iter.peek()?.proposal.clone();
995        let certificate = scheme.assemble_certificate(iter.map(|n| n.vote.clone()))?;
996
997        Some(Self {
998            proposal,
999            certificate,
1000        })
1001    }
1002
1003    /// Returns the round associated with the notarized proposal.
1004    pub fn round(&self) -> Round {
1005        self.proposal.round
1006    }
1007}
1008
1009impl<S: Scheme, D: Digest> PartialEq for Notarization<S, D> {
1010    fn eq(&self, other: &Self) -> bool {
1011        self.proposal == other.proposal && self.certificate == other.certificate
1012    }
1013}
1014
1015impl<S: Scheme, D: Digest> Eq for Notarization<S, D> {}
1016
1017impl<S: Scheme, D: Digest> Hash for Notarization<S, D> {
1018    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
1019        self.proposal.hash(state);
1020        self.certificate.hash(state);
1021    }
1022}
1023
1024impl<S: Scheme, D: Digest> Notarization<S, D> {
1025    /// Verifies the notarization certificate against the provided signing scheme.
1026    ///
1027    /// This ensures that the certificate is valid for the claimed proposal.
1028    pub fn verify<R: Rng + CryptoRng>(&self, rng: &mut R, scheme: &S, namespace: &[u8]) -> bool {
1029        scheme.verify_certificate(
1030            rng,
1031            namespace,
1032            VoteContext::Notarize {
1033                proposal: &self.proposal,
1034            },
1035            &self.certificate,
1036        )
1037    }
1038}
1039
1040impl<S: Scheme, D: Digest> Write for Notarization<S, D> {
1041    fn write(&self, writer: &mut impl BufMut) {
1042        self.proposal.write(writer);
1043        self.certificate.write(writer);
1044    }
1045}
1046
1047impl<S: Scheme, D: Digest> EncodeSize for Notarization<S, D> {
1048    fn encode_size(&self) -> usize {
1049        self.proposal.encode_size() + self.certificate.encode_size()
1050    }
1051}
1052
1053impl<S: Scheme, D: Digest> Read for Notarization<S, D> {
1054    type Cfg = <S::Certificate as Read>::Cfg;
1055
1056    fn read_cfg(reader: &mut impl Buf, cfg: &Self::Cfg) -> Result<Self, Error> {
1057        let proposal = Proposal::read(reader)?;
1058        let certificate = S::Certificate::read_cfg(reader, cfg)?;
1059
1060        Ok(Self {
1061            proposal,
1062            certificate,
1063        })
1064    }
1065}
1066
1067impl<S: Scheme, D: Digest> Epochable for Notarization<S, D> {
1068    type Epoch = Epoch;
1069
1070    fn epoch(&self) -> Epoch {
1071        self.proposal.epoch()
1072    }
1073}
1074
1075impl<S: Scheme, D: Digest> Viewable for Notarization<S, D> {
1076    type View = View;
1077
1078    fn view(&self) -> View {
1079        self.proposal.view()
1080    }
1081}
1082
1083/// Validator vote for nullifying the current round, i.e. skip the current round.
1084/// This is typically used when the leader is unresponsive or fails to propose a valid block.
1085#[derive(Clone, Debug)]
1086pub struct Nullify<S: Scheme> {
1087    /// The round to be nullified (skipped).
1088    pub round: Round,
1089    /// Scheme-specific vote material.
1090    pub vote: Vote<S>,
1091}
1092
1093impl<S: Scheme> PartialEq for Nullify<S> {
1094    fn eq(&self, other: &Self) -> bool {
1095        self.round == other.round && self.vote == other.vote
1096    }
1097}
1098
1099impl<S: Scheme> Eq for Nullify<S> {}
1100
1101impl<S: Scheme> Hash for Nullify<S> {
1102    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
1103        self.round.hash(state);
1104        self.vote.hash(state);
1105    }
1106}
1107
1108impl<S: Scheme> Nullify<S> {
1109    /// Signs a nullify vote for the given round.
1110    pub fn sign<D: Digest>(scheme: &S, namespace: &[u8], round: Round) -> Option<Self> {
1111        let vote = scheme.sign_vote::<D>(namespace, VoteContext::Nullify { round })?;
1112
1113        Some(Self { round, vote })
1114    }
1115
1116    /// Verifies the nullify vote against the provided signing scheme.
1117    ///
1118    /// This ensures that the nullify signature is valid for the given round.
1119    pub fn verify<D: Digest>(&self, scheme: &S, namespace: &[u8]) -> bool {
1120        scheme.verify_vote::<D>(
1121            namespace,
1122            VoteContext::Nullify { round: self.round },
1123            &self.vote,
1124        )
1125    }
1126
1127    /// Returns the round associated with this nullify vote.
1128    pub fn round(&self) -> Round {
1129        self.round
1130    }
1131}
1132
1133impl<S: Scheme> Write for Nullify<S> {
1134    fn write(&self, writer: &mut impl BufMut) {
1135        self.round.write(writer);
1136        self.vote.write(writer);
1137    }
1138}
1139
1140impl<S: Scheme> EncodeSize for Nullify<S> {
1141    fn encode_size(&self) -> usize {
1142        self.round.encode_size() + self.vote.encode_size()
1143    }
1144}
1145
1146impl<S: Scheme> Read for Nullify<S> {
1147    type Cfg = ();
1148
1149    fn read_cfg(reader: &mut impl Buf, _: &()) -> Result<Self, Error> {
1150        let round = Round::read(reader)?;
1151        let vote = Vote::read(reader)?;
1152
1153        Ok(Self { round, vote })
1154    }
1155}
1156
1157impl<S: Scheme> Attributable for Nullify<S> {
1158    fn signer(&self) -> u32 {
1159        self.vote.signer
1160    }
1161}
1162
1163impl<S: Scheme> Epochable for Nullify<S> {
1164    type Epoch = Epoch;
1165
1166    fn epoch(&self) -> Epoch {
1167        self.round.epoch()
1168    }
1169}
1170
1171impl<S: Scheme> Viewable for Nullify<S> {
1172    type View = View;
1173
1174    fn view(&self) -> View {
1175        self.round.view()
1176    }
1177}
1178
1179/// Aggregated nullification certificate recovered from nullify votes.
1180/// When a view is nullified, the consensus moves to the next view without finalizing a block.
1181#[derive(Clone, Debug)]
1182pub struct Nullification<S: Scheme> {
1183    /// The round in which this nullification is made.
1184    pub round: Round,
1185    /// The recovered certificate for the nullification.
1186    pub certificate: S::Certificate,
1187}
1188
1189impl<S: Scheme> Nullification<S> {
1190    /// Builds a nullification certificate from nullify votes from the same round.
1191    pub fn from_nullifies<'a>(
1192        scheme: &S,
1193        nullifies: impl IntoIterator<Item = &'a Nullify<S>>,
1194    ) -> Option<Self> {
1195        let mut iter = nullifies.into_iter().peekable();
1196        let round = iter.peek()?.round;
1197        let certificate = scheme.assemble_certificate(iter.map(|n| n.vote.clone()))?;
1198
1199        Some(Self { round, certificate })
1200    }
1201
1202    /// Returns the round associated with this nullification.
1203    pub fn round(&self) -> Round {
1204        self.round
1205    }
1206}
1207
1208impl<S: Scheme> PartialEq for Nullification<S> {
1209    fn eq(&self, other: &Self) -> bool {
1210        self.round == other.round && self.certificate == other.certificate
1211    }
1212}
1213
1214impl<S: Scheme> Eq for Nullification<S> {}
1215
1216impl<S: Scheme> Hash for Nullification<S> {
1217    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
1218        self.round.hash(state);
1219        self.certificate.hash(state);
1220    }
1221}
1222
1223impl<S: Scheme> Write for Nullification<S> {
1224    fn write(&self, writer: &mut impl BufMut) {
1225        self.round.write(writer);
1226        self.certificate.write(writer);
1227    }
1228}
1229
1230impl<S: Scheme> Nullification<S> {
1231    /// Verifies the nullification certificate against the provided signing scheme.
1232    ///
1233    /// This ensures that the certificate is valid for the claimed round.
1234    pub fn verify<R: Rng + CryptoRng, D: Digest>(
1235        &self,
1236        rng: &mut R,
1237        scheme: &S,
1238        namespace: &[u8],
1239    ) -> bool {
1240        scheme.verify_certificate::<_, D>(
1241            rng,
1242            namespace,
1243            VoteContext::Nullify { round: self.round },
1244            &self.certificate,
1245        )
1246    }
1247}
1248
1249impl<S: Scheme> EncodeSize for Nullification<S> {
1250    fn encode_size(&self) -> usize {
1251        self.round.encode_size() + self.certificate.encode_size()
1252    }
1253}
1254
1255impl<S: Scheme> Read for Nullification<S> {
1256    type Cfg = <S::Certificate as Read>::Cfg;
1257
1258    fn read_cfg(reader: &mut impl Buf, cfg: &Self::Cfg) -> Result<Self, Error> {
1259        let round = Round::read(reader)?;
1260        let certificate = S::Certificate::read_cfg(reader, cfg)?;
1261
1262        Ok(Self { round, certificate })
1263    }
1264}
1265
1266impl<S: Scheme> Epochable for Nullification<S> {
1267    type Epoch = Epoch;
1268
1269    fn epoch(&self) -> Epoch {
1270        self.round.epoch()
1271    }
1272}
1273
1274impl<S: Scheme> Viewable for Nullification<S> {
1275    type View = View;
1276
1277    fn view(&self) -> View {
1278        self.round.view()
1279    }
1280}
1281
1282/// Validator vote to finalize a proposal.
1283/// This happens after a proposal has been notarized, confirming it as the canonical block
1284/// for this round.
1285#[derive(Clone, Debug)]
1286pub struct Finalize<S: Scheme, D: Digest> {
1287    /// Proposal being finalized.
1288    pub proposal: Proposal<D>,
1289    /// Scheme-specific vote material.
1290    pub vote: Vote<S>,
1291}
1292
1293impl<S: Scheme, D: Digest> Finalize<S, D> {
1294    /// Returns the round associated with this finalize vote.
1295    pub fn round(&self) -> Round {
1296        self.proposal.round
1297    }
1298}
1299
1300impl<S: Scheme, D: Digest> PartialEq for Finalize<S, D> {
1301    fn eq(&self, other: &Self) -> bool {
1302        self.proposal == other.proposal && self.vote == other.vote
1303    }
1304}
1305
1306impl<S: Scheme, D: Digest> Eq for Finalize<S, D> {}
1307
1308impl<S: Scheme, D: Digest> Hash for Finalize<S, D> {
1309    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
1310        self.proposal.hash(state);
1311        self.vote.hash(state);
1312    }
1313}
1314
1315impl<S: Scheme, D: Digest> Finalize<S, D> {
1316    /// Signs a finalize vote for the provided proposal.
1317    pub fn sign(scheme: &S, namespace: &[u8], proposal: Proposal<D>) -> Option<Self> {
1318        let vote = scheme.sign_vote(
1319            namespace,
1320            VoteContext::Finalize {
1321                proposal: &proposal,
1322            },
1323        )?;
1324
1325        Some(Self { proposal, vote })
1326    }
1327
1328    /// Verifies the finalize vote against the provided signing scheme.
1329    ///
1330    /// This ensures that the finalize signature is valid for the claimed proposal.
1331    pub fn verify(&self, scheme: &S, namespace: &[u8]) -> bool {
1332        scheme.verify_vote(
1333            namespace,
1334            VoteContext::Finalize {
1335                proposal: &self.proposal,
1336            },
1337            &self.vote,
1338        )
1339    }
1340}
1341
1342impl<S: Scheme, D: Digest> Write for Finalize<S, D> {
1343    fn write(&self, writer: &mut impl BufMut) {
1344        self.proposal.write(writer);
1345        self.vote.write(writer);
1346    }
1347}
1348
1349impl<S: Scheme, D: Digest> EncodeSize for Finalize<S, D> {
1350    fn encode_size(&self) -> usize {
1351        self.proposal.encode_size() + self.vote.encode_size()
1352    }
1353}
1354
1355impl<S: Scheme, D: Digest> Read for Finalize<S, D> {
1356    type Cfg = ();
1357
1358    fn read_cfg(reader: &mut impl Buf, _: &()) -> Result<Self, Error> {
1359        let proposal = Proposal::read(reader)?;
1360        let vote = Vote::read(reader)?;
1361
1362        Ok(Self { proposal, vote })
1363    }
1364}
1365
1366impl<S: Scheme, D: Digest> Attributable for Finalize<S, D> {
1367    fn signer(&self) -> u32 {
1368        self.vote.signer
1369    }
1370}
1371
1372impl<S: Scheme, D: Digest> Epochable for Finalize<S, D> {
1373    type Epoch = Epoch;
1374
1375    fn epoch(&self) -> Epoch {
1376        self.proposal.epoch()
1377    }
1378}
1379
1380impl<S: Scheme, D: Digest> Viewable for Finalize<S, D> {
1381    type View = View;
1382
1383    fn view(&self) -> View {
1384        self.proposal.view()
1385    }
1386}
1387
1388/// Aggregated finalization certificate recovered from finalize votes.
1389/// When a proposal is finalized, it becomes the canonical block for its view.
1390///
1391/// Some signing schemes embed an additional randomness seed in the certificate (used for
1392/// leader rotation), it can be accessed via [`Scheme::seed`].
1393#[derive(Clone, Debug)]
1394pub struct Finalization<S: Scheme, D: Digest> {
1395    /// The proposal that has been finalized.
1396    pub proposal: Proposal<D>,
1397    /// The recovered certificate for the proposal.
1398    pub certificate: S::Certificate,
1399}
1400
1401impl<S: Scheme, D: Digest> Finalization<S, D> {
1402    /// Builds a finalization certificate from finalize votes for the same proposal.
1403    pub fn from_finalizes<'a>(
1404        scheme: &S,
1405        finalizes: impl IntoIterator<Item = &'a Finalize<S, D>>,
1406    ) -> Option<Self> {
1407        let mut iter = finalizes.into_iter().peekable();
1408        let proposal = iter.peek()?.proposal.clone();
1409        let certificate = scheme.assemble_certificate(iter.map(|f| f.vote.clone()))?;
1410
1411        Some(Self {
1412            proposal,
1413            certificate,
1414        })
1415    }
1416
1417    /// Returns the round associated with the finalized proposal.
1418    pub fn round(&self) -> Round {
1419        self.proposal.round
1420    }
1421}
1422
1423impl<S: Scheme, D: Digest> PartialEq for Finalization<S, D> {
1424    fn eq(&self, other: &Self) -> bool {
1425        self.proposal == other.proposal && self.certificate == other.certificate
1426    }
1427}
1428
1429impl<S: Scheme, D: Digest> Eq for Finalization<S, D> {}
1430
1431impl<S: Scheme, D: Digest> Hash for Finalization<S, D> {
1432    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
1433        self.proposal.hash(state);
1434        self.certificate.hash(state);
1435    }
1436}
1437
1438impl<S: Scheme, D: Digest> Finalization<S, D> {
1439    /// Verifies the finalization certificate against the provided signing scheme.
1440    ///
1441    /// This ensures that the certificate is valid for the claimed proposal.
1442    pub fn verify<R: Rng + CryptoRng>(&self, rng: &mut R, scheme: &S, namespace: &[u8]) -> bool {
1443        scheme.verify_certificate(
1444            rng,
1445            namespace,
1446            VoteContext::Finalize {
1447                proposal: &self.proposal,
1448            },
1449            &self.certificate,
1450        )
1451    }
1452}
1453
1454impl<S: Scheme, D: Digest> Write for Finalization<S, D> {
1455    fn write(&self, writer: &mut impl BufMut) {
1456        self.proposal.write(writer);
1457        self.certificate.write(writer);
1458    }
1459}
1460
1461impl<S: Scheme, D: Digest> EncodeSize for Finalization<S, D> {
1462    fn encode_size(&self) -> usize {
1463        self.proposal.encode_size() + self.certificate.encode_size()
1464    }
1465}
1466
1467impl<S: Scheme, D: Digest> Read for Finalization<S, D> {
1468    type Cfg = <S::Certificate as Read>::Cfg;
1469
1470    fn read_cfg(reader: &mut impl Buf, cfg: &Self::Cfg) -> Result<Self, Error> {
1471        let proposal = Proposal::read(reader)?;
1472        let certificate = S::Certificate::read_cfg(reader, cfg)?;
1473
1474        Ok(Self {
1475            proposal,
1476            certificate,
1477        })
1478    }
1479}
1480
1481impl<S: Scheme, D: Digest> Epochable for Finalization<S, D> {
1482    type Epoch = Epoch;
1483
1484    fn epoch(&self) -> Epoch {
1485        self.proposal.epoch()
1486    }
1487}
1488
1489impl<S: Scheme, D: Digest> Viewable for Finalization<S, D> {
1490    type View = View;
1491
1492    fn view(&self) -> View {
1493        self.proposal.view()
1494    }
1495}
1496
1497/// Backfiller is a message type for requesting and receiving missing consensus artifacts.
1498/// This is used to synchronize validators that have fallen behind or just joined the network.
1499#[derive(Clone, Debug, PartialEq)]
1500pub enum Backfiller<S: Scheme, D: Digest> {
1501    /// Request for missing notarizations and nullifications
1502    Request(Request),
1503    /// Response containing requested notarizations and nullifications
1504    Response(Response<S, D>),
1505}
1506
1507impl<S: Scheme, D: Digest> Write for Backfiller<S, D> {
1508    fn write(&self, writer: &mut impl BufMut) {
1509        match self {
1510            Backfiller::Request(request) => {
1511                0u8.write(writer);
1512                request.write(writer);
1513            }
1514            Backfiller::Response(response) => {
1515                1u8.write(writer);
1516                response.write(writer);
1517            }
1518        }
1519    }
1520}
1521
1522impl<S: Scheme, D: Digest> EncodeSize for Backfiller<S, D> {
1523    fn encode_size(&self) -> usize {
1524        1 + match self {
1525            Backfiller::Request(v) => v.encode_size(),
1526            Backfiller::Response(v) => v.encode_size(),
1527        }
1528    }
1529}
1530
1531impl<S: Scheme, D: Digest> Read for Backfiller<S, D> {
1532    type Cfg = (usize, <S::Certificate as Read>::Cfg);
1533
1534    fn read_cfg(reader: &mut impl Buf, cfg: &Self::Cfg) -> Result<Self, Error> {
1535        let tag = <u8>::read(reader)?;
1536        match tag {
1537            0 => {
1538                let (max_len, _) = cfg;
1539                let v = Request::read_cfg(reader, max_len)?;
1540                Ok(Backfiller::Request(v))
1541            }
1542            1 => {
1543                let v = Response::<S, D>::read_cfg(reader, cfg)?;
1544                Ok(Backfiller::Response(v))
1545            }
1546            _ => Err(Error::Invalid(
1547                "consensus::simplex::Backfiller",
1548                "Invalid type",
1549            )),
1550        }
1551    }
1552}
1553
1554/// Request is a message to request missing notarizations and nullifications.
1555/// This is used by validators who need to catch up with the consensus state.
1556#[derive(Clone, Debug, PartialEq)]
1557pub struct Request {
1558    /// Unique identifier for this request (used to match responses)
1559    pub id: u64,
1560    /// Views for which notarizations are requested
1561    pub notarizations: Vec<View>,
1562    /// Views for which nullifications are requested
1563    pub nullifications: Vec<View>,
1564}
1565
1566impl Request {
1567    /// Creates a new request for missing notarizations and nullifications.
1568    pub fn new(id: u64, notarizations: Vec<View>, nullifications: Vec<View>) -> Self {
1569        Request {
1570            id,
1571            notarizations,
1572            nullifications,
1573        }
1574    }
1575}
1576
1577impl Write for Request {
1578    fn write(&self, writer: &mut impl BufMut) {
1579        UInt(self.id).write(writer);
1580        self.notarizations.write(writer);
1581        self.nullifications.write(writer);
1582    }
1583}
1584
1585impl EncodeSize for Request {
1586    fn encode_size(&self) -> usize {
1587        UInt(self.id).encode_size()
1588            + self.notarizations.encode_size()
1589            + self.nullifications.encode_size()
1590    }
1591}
1592
1593impl Read for Request {
1594    type Cfg = usize;
1595
1596    fn read_cfg(reader: &mut impl Buf, max_len: &usize) -> Result<Self, Error> {
1597        let id = UInt::read(reader)?.into();
1598        let mut views = HashSet::new();
1599        let notarizations = Vec::<View>::read_range(reader, ..=*max_len)?;
1600        for view in notarizations.iter() {
1601            if !views.insert(view) {
1602                return Err(Error::Invalid(
1603                    "consensus::simplex::Request",
1604                    "Duplicate notarization",
1605                ));
1606            }
1607        }
1608        let remaining = max_len - notarizations.len();
1609        views.clear();
1610        let nullifications = Vec::<View>::read_range(reader, ..=remaining)?;
1611        for view in nullifications.iter() {
1612            if !views.insert(view) {
1613                return Err(Error::Invalid(
1614                    "consensus::simplex::Request",
1615                    "Duplicate nullification",
1616                ));
1617            }
1618        }
1619        Ok(Request {
1620            id,
1621            notarizations,
1622            nullifications,
1623        })
1624    }
1625}
1626
1627/// Response is a message containing the requested notarizations and nullifications.
1628/// This is sent in response to a Request message.
1629#[derive(Clone, Debug, PartialEq)]
1630pub struct Response<S: Scheme, D: Digest> {
1631    /// Identifier matching the original request
1632    pub id: u64,
1633    /// Notarizations for the requested views
1634    pub notarizations: Vec<Notarization<S, D>>,
1635    /// Nullifications for the requested views
1636    pub nullifications: Vec<Nullification<S>>,
1637}
1638
1639impl<S: Scheme, D: Digest> Response<S, D> {
1640    /// Creates a new response with the given id, notarizations, and nullifications.
1641    pub fn new(
1642        id: u64,
1643        notarizations: Vec<Notarization<S, D>>,
1644        nullifications: Vec<Nullification<S>>,
1645    ) -> Self {
1646        Response {
1647            id,
1648            notarizations,
1649            nullifications,
1650        }
1651    }
1652
1653    /// Verifies the certificates contained in this response against the signing scheme.
1654    pub fn verify<R: Rng + CryptoRng>(&self, rng: &mut R, scheme: &S, namespace: &[u8]) -> bool {
1655        // Prepare to verify
1656        if self.notarizations.is_empty() && self.nullifications.is_empty() {
1657            return true;
1658        }
1659
1660        let notarizations = self.notarizations.iter().map(|notarization| {
1661            let context = VoteContext::Notarize {
1662                proposal: &notarization.proposal,
1663            };
1664
1665            (context, &notarization.certificate)
1666        });
1667
1668        let nullifications = self.nullifications.iter().map(|nullification| {
1669            let context = VoteContext::Nullify {
1670                round: nullification.round,
1671            };
1672
1673            (context, &nullification.certificate)
1674        });
1675
1676        scheme.verify_certificates(rng, namespace, notarizations.chain(nullifications))
1677    }
1678}
1679
1680impl<S: Scheme, D: Digest> Write for Response<S, D> {
1681    fn write(&self, writer: &mut impl BufMut) {
1682        UInt(self.id).write(writer);
1683        self.notarizations.write(writer);
1684        self.nullifications.write(writer);
1685    }
1686}
1687
1688impl<S: Scheme, D: Digest> EncodeSize for Response<S, D> {
1689    fn encode_size(&self) -> usize {
1690        UInt(self.id).encode_size()
1691            + self.notarizations.encode_size()
1692            + self.nullifications.encode_size()
1693    }
1694}
1695
1696impl<S: Scheme, D: Digest> Read for Response<S, D> {
1697    type Cfg = (usize, <S::Certificate as Read>::Cfg);
1698
1699    fn read_cfg(reader: &mut impl Buf, cfg: &Self::Cfg) -> Result<Self, Error> {
1700        let (max_len, certificate_cfg) = cfg;
1701        let id = UInt::read(reader)?.into();
1702        let mut views = HashSet::new();
1703        let notarizations = Vec::<Notarization<S, D>>::read_cfg(
1704            reader,
1705            &((..=*max_len).into(), certificate_cfg.clone()),
1706        )?;
1707        for notarization in notarizations.iter() {
1708            if !views.insert(notarization.view()) {
1709                return Err(Error::Invalid(
1710                    "consensus::simplex::Response",
1711                    "Duplicate notarization",
1712                ));
1713            }
1714        }
1715        let remaining = max_len - notarizations.len();
1716        views.clear();
1717        let nullifications = Vec::<Nullification<S>>::read_cfg(
1718            reader,
1719            &((..=remaining).into(), certificate_cfg.clone()),
1720        )?;
1721        for nullification in nullifications.iter() {
1722            if !views.insert(nullification.view()) {
1723                return Err(Error::Invalid(
1724                    "consensus::simplex::Response",
1725                    "Duplicate nullification",
1726                ));
1727            }
1728        }
1729        Ok(Response {
1730            id,
1731            notarizations,
1732            nullifications,
1733        })
1734    }
1735}
1736
1737/// Activity represents all possible activities that can occur in the consensus protocol.
1738/// This includes both regular consensus messages and fault evidence.
1739///
1740/// # Verification
1741///
1742/// Some activities issued by consensus are not guaranteed to be cryptographically verified (i.e. if not needed
1743/// to produce a minimum quorum certificate). Use [`Activity::verified`] to check if an activity may not be verified,
1744/// and [`Activity::verify`] to perform verification.
1745///
1746/// # Activity Filtering
1747///
1748/// For **non-attributable** schemes like [`crate::simplex::signing_scheme::bls12381_threshold`], exposing
1749/// per-validator activity as fault evidence is not safe: with threshold cryptography, any `t` valid partial signatures can
1750/// be used to forge a partial signature for any player.
1751///
1752/// Use [`crate::simplex::signing_scheme::reporter::AttributableReporter`] to automatically filter and
1753/// verify activities based on [`Scheme::is_attributable`].
1754#[derive(Clone, Debug)]
1755pub enum Activity<S: Scheme, D: Digest> {
1756    /// A validator's notarize vote over a proposal.
1757    Notarize(Notarize<S, D>),
1758    /// A recovered certificate for a notarization (scheme-specific).
1759    Notarization(Notarization<S, D>),
1760    /// A validator's nullify vote used to skip the current view.
1761    Nullify(Nullify<S>),
1762    /// A recovered certificate for a nullification (scheme-specific).
1763    Nullification(Nullification<S>),
1764    /// A validator's finalize vote over a proposal.
1765    Finalize(Finalize<S, D>),
1766    /// A recovered certificate for a finalization (scheme-specific).
1767    Finalization(Finalization<S, D>),
1768    /// Evidence of a validator sending conflicting notarizes (Byzantine behavior).
1769    ConflictingNotarize(ConflictingNotarize<S, D>),
1770    /// Evidence of a validator sending conflicting finalizes (Byzantine behavior).
1771    ConflictingFinalize(ConflictingFinalize<S, D>),
1772    /// Evidence of a validator sending both nullify and finalize for the same view (Byzantine behavior).
1773    NullifyFinalize(NullifyFinalize<S, D>),
1774}
1775
1776impl<S: Scheme, D: Digest> PartialEq for Activity<S, D> {
1777    fn eq(&self, other: &Self) -> bool {
1778        match (self, other) {
1779            (Activity::Notarize(a), Activity::Notarize(b)) => a == b,
1780            (Activity::Notarization(a), Activity::Notarization(b)) => a == b,
1781            (Activity::Nullify(a), Activity::Nullify(b)) => a == b,
1782            (Activity::Nullification(a), Activity::Nullification(b)) => a == b,
1783            (Activity::Finalize(a), Activity::Finalize(b)) => a == b,
1784            (Activity::Finalization(a), Activity::Finalization(b)) => a == b,
1785            (Activity::ConflictingNotarize(a), Activity::ConflictingNotarize(b)) => a == b,
1786            (Activity::ConflictingFinalize(a), Activity::ConflictingFinalize(b)) => a == b,
1787            (Activity::NullifyFinalize(a), Activity::NullifyFinalize(b)) => a == b,
1788            _ => false,
1789        }
1790    }
1791}
1792
1793impl<S: Scheme, D: Digest> Eq for Activity<S, D> {}
1794
1795impl<S: Scheme, D: Digest> Hash for Activity<S, D> {
1796    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
1797        match self {
1798            Activity::Notarize(v) => {
1799                0u8.hash(state);
1800                v.hash(state);
1801            }
1802            Activity::Notarization(v) => {
1803                1u8.hash(state);
1804                v.hash(state);
1805            }
1806            Activity::Nullify(v) => {
1807                2u8.hash(state);
1808                v.hash(state);
1809            }
1810            Activity::Nullification(v) => {
1811                3u8.hash(state);
1812                v.hash(state);
1813            }
1814            Activity::Finalize(v) => {
1815                4u8.hash(state);
1816                v.hash(state);
1817            }
1818            Activity::Finalization(v) => {
1819                5u8.hash(state);
1820                v.hash(state);
1821            }
1822            Activity::ConflictingNotarize(v) => {
1823                6u8.hash(state);
1824                v.hash(state);
1825            }
1826            Activity::ConflictingFinalize(v) => {
1827                7u8.hash(state);
1828                v.hash(state);
1829            }
1830            Activity::NullifyFinalize(v) => {
1831                8u8.hash(state);
1832                v.hash(state);
1833            }
1834        }
1835    }
1836}
1837
1838impl<S: Scheme, D: Digest> Activity<S, D> {
1839    /// Indicates whether the activity is guaranteed to have been verified by consensus.
1840    pub fn verified(&self) -> bool {
1841        match self {
1842            Activity::Notarize(_) => false,
1843            Activity::Notarization(_) => true,
1844            Activity::Nullify(_) => false,
1845            Activity::Nullification(_) => true,
1846            Activity::Finalize(_) => false,
1847            Activity::Finalization(_) => true,
1848            Activity::ConflictingNotarize(_) => false,
1849            Activity::ConflictingFinalize(_) => false,
1850            Activity::NullifyFinalize(_) => false,
1851        }
1852    }
1853
1854    /// Verifies the validity of this activity against the signing scheme.
1855    ///
1856    /// This method **always** performs verification regardless of whether the activity has been
1857    /// previously verified. Callers can use [`Activity::verified`] to check if verification is
1858    /// necessary before calling this method.
1859    pub fn verify<R: Rng + CryptoRng>(&self, rng: &mut R, scheme: &S, namespace: &[u8]) -> bool {
1860        match self {
1861            Activity::Notarize(n) => n.verify(scheme, namespace),
1862            Activity::Notarization(n) => n.verify(rng, scheme, namespace),
1863            Activity::Nullify(n) => n.verify::<D>(scheme, namespace),
1864            Activity::Nullification(n) => n.verify::<R, D>(rng, scheme, namespace),
1865            Activity::Finalize(f) => f.verify(scheme, namespace),
1866            Activity::Finalization(f) => f.verify(rng, scheme, namespace),
1867            Activity::ConflictingNotarize(c) => c.verify(scheme, namespace),
1868            Activity::ConflictingFinalize(c) => c.verify(scheme, namespace),
1869            Activity::NullifyFinalize(c) => c.verify(scheme, namespace),
1870        }
1871    }
1872}
1873
1874impl<S: Scheme, D: Digest> Write for Activity<S, D> {
1875    fn write(&self, writer: &mut impl BufMut) {
1876        match self {
1877            Activity::Notarize(v) => {
1878                0u8.write(writer);
1879                v.write(writer);
1880            }
1881            Activity::Notarization(v) => {
1882                1u8.write(writer);
1883                v.write(writer);
1884            }
1885            Activity::Nullify(v) => {
1886                2u8.write(writer);
1887                v.write(writer);
1888            }
1889            Activity::Nullification(v) => {
1890                3u8.write(writer);
1891                v.write(writer);
1892            }
1893            Activity::Finalize(v) => {
1894                4u8.write(writer);
1895                v.write(writer);
1896            }
1897            Activity::Finalization(v) => {
1898                5u8.write(writer);
1899                v.write(writer);
1900            }
1901            Activity::ConflictingNotarize(v) => {
1902                6u8.write(writer);
1903                v.write(writer);
1904            }
1905            Activity::ConflictingFinalize(v) => {
1906                7u8.write(writer);
1907                v.write(writer);
1908            }
1909            Activity::NullifyFinalize(v) => {
1910                8u8.write(writer);
1911                v.write(writer);
1912            }
1913        }
1914    }
1915}
1916
1917impl<S: Scheme, D: Digest> EncodeSize for Activity<S, D> {
1918    fn encode_size(&self) -> usize {
1919        1 + match self {
1920            Activity::Notarize(v) => v.encode_size(),
1921            Activity::Notarization(v) => v.encode_size(),
1922            Activity::Nullify(v) => v.encode_size(),
1923            Activity::Nullification(v) => v.encode_size(),
1924            Activity::Finalize(v) => v.encode_size(),
1925            Activity::Finalization(v) => v.encode_size(),
1926            Activity::ConflictingNotarize(v) => v.encode_size(),
1927            Activity::ConflictingFinalize(v) => v.encode_size(),
1928            Activity::NullifyFinalize(v) => v.encode_size(),
1929        }
1930    }
1931}
1932
1933impl<S: Scheme, D: Digest> Read for Activity<S, D> {
1934    type Cfg = <S::Certificate as Read>::Cfg;
1935
1936    fn read_cfg(reader: &mut impl Buf, cfg: &Self::Cfg) -> Result<Self, Error> {
1937        let tag = <u8>::read(reader)?;
1938        match tag {
1939            0 => {
1940                let v = Notarize::<S, D>::read(reader)?;
1941                Ok(Activity::Notarize(v))
1942            }
1943            1 => {
1944                let v = Notarization::<S, D>::read_cfg(reader, cfg)?;
1945                Ok(Activity::Notarization(v))
1946            }
1947            2 => {
1948                let v = Nullify::<S>::read(reader)?;
1949                Ok(Activity::Nullify(v))
1950            }
1951            3 => {
1952                let v = Nullification::<S>::read_cfg(reader, cfg)?;
1953                Ok(Activity::Nullification(v))
1954            }
1955            4 => {
1956                let v = Finalize::<S, D>::read(reader)?;
1957                Ok(Activity::Finalize(v))
1958            }
1959            5 => {
1960                let v = Finalization::<S, D>::read_cfg(reader, cfg)?;
1961                Ok(Activity::Finalization(v))
1962            }
1963            6 => {
1964                let v = ConflictingNotarize::<S, D>::read(reader)?;
1965                Ok(Activity::ConflictingNotarize(v))
1966            }
1967            7 => {
1968                let v = ConflictingFinalize::<S, D>::read(reader)?;
1969                Ok(Activity::ConflictingFinalize(v))
1970            }
1971            8 => {
1972                let v = NullifyFinalize::<S, D>::read(reader)?;
1973                Ok(Activity::NullifyFinalize(v))
1974            }
1975            _ => Err(Error::Invalid(
1976                "consensus::simplex::Activity",
1977                "Invalid type",
1978            )),
1979        }
1980    }
1981}
1982
1983impl<S: Scheme, D: Digest> Epochable for Activity<S, D> {
1984    type Epoch = Epoch;
1985
1986    fn epoch(&self) -> Epoch {
1987        match self {
1988            Activity::Notarize(v) => v.epoch(),
1989            Activity::Notarization(v) => v.epoch(),
1990            Activity::Nullify(v) => v.epoch(),
1991            Activity::Nullification(v) => v.epoch(),
1992            Activity::Finalize(v) => v.epoch(),
1993            Activity::Finalization(v) => v.epoch(),
1994            Activity::ConflictingNotarize(v) => v.epoch(),
1995            Activity::ConflictingFinalize(v) => v.epoch(),
1996            Activity::NullifyFinalize(v) => v.epoch(),
1997        }
1998    }
1999}
2000
2001impl<S: Scheme, D: Digest> Viewable for Activity<S, D> {
2002    type View = View;
2003
2004    fn view(&self) -> View {
2005        match self {
2006            Activity::Notarize(v) => v.view(),
2007            Activity::Notarization(v) => v.view(),
2008            Activity::Nullify(v) => v.view(),
2009            Activity::Nullification(v) => v.view(),
2010            Activity::Finalize(v) => v.view(),
2011            Activity::Finalization(v) => v.view(),
2012            Activity::ConflictingNotarize(v) => v.view(),
2013            Activity::ConflictingFinalize(v) => v.view(),
2014            Activity::NullifyFinalize(v) => v.view(),
2015        }
2016    }
2017}
2018
2019/// ConflictingNotarize represents evidence of a Byzantine validator sending conflicting notarizes.
2020/// This is used to prove that a validator has equivocated (voted for different proposals in the same view).
2021#[derive(Clone, Debug)]
2022pub struct ConflictingNotarize<S: Scheme, D: Digest> {
2023    /// The first conflicting notarize
2024    notarize_1: Notarize<S, D>,
2025    /// The second conflicting notarize
2026    notarize_2: Notarize<S, D>,
2027}
2028
2029impl<S: Scheme, D: Digest> PartialEq for ConflictingNotarize<S, D> {
2030    fn eq(&self, other: &Self) -> bool {
2031        self.notarize_1 == other.notarize_1 && self.notarize_2 == other.notarize_2
2032    }
2033}
2034
2035impl<S: Scheme, D: Digest> Eq for ConflictingNotarize<S, D> {}
2036
2037impl<S: Scheme, D: Digest> Hash for ConflictingNotarize<S, D> {
2038    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
2039        self.notarize_1.hash(state);
2040        self.notarize_2.hash(state);
2041    }
2042}
2043
2044impl<S: Scheme, D: Digest> ConflictingNotarize<S, D> {
2045    /// Creates a new conflicting notarize evidence from two conflicting notarizes.
2046    pub fn new(notarize_1: Notarize<S, D>, notarize_2: Notarize<S, D>) -> Self {
2047        assert_eq!(notarize_1.round(), notarize_2.round());
2048        assert_eq!(notarize_1.signer(), notarize_2.signer());
2049
2050        ConflictingNotarize {
2051            notarize_1,
2052            notarize_2,
2053        }
2054    }
2055
2056    /// Verifies that both conflicting signatures are valid, proving Byzantine behavior.
2057    pub fn verify(&self, scheme: &S, namespace: &[u8]) -> bool {
2058        self.notarize_1.verify(scheme, namespace) && self.notarize_2.verify(scheme, namespace)
2059    }
2060}
2061
2062impl<S: Scheme, D: Digest> Attributable for ConflictingNotarize<S, D> {
2063    fn signer(&self) -> u32 {
2064        self.notarize_1.signer()
2065    }
2066}
2067
2068impl<S: Scheme, D: Digest> Epochable for ConflictingNotarize<S, D> {
2069    type Epoch = Epoch;
2070
2071    fn epoch(&self) -> Epoch {
2072        self.notarize_1.epoch()
2073    }
2074}
2075
2076impl<S: Scheme, D: Digest> Viewable for ConflictingNotarize<S, D> {
2077    type View = View;
2078
2079    fn view(&self) -> View {
2080        self.notarize_1.view()
2081    }
2082}
2083
2084impl<S: Scheme, D: Digest> Write for ConflictingNotarize<S, D> {
2085    fn write(&self, writer: &mut impl BufMut) {
2086        self.notarize_1.write(writer);
2087        self.notarize_2.write(writer);
2088    }
2089}
2090
2091impl<S: Scheme, D: Digest> Read for ConflictingNotarize<S, D> {
2092    type Cfg = ();
2093
2094    fn read_cfg(reader: &mut impl Buf, _: &()) -> Result<Self, Error> {
2095        let notarize_1 = Notarize::read(reader)?;
2096        let notarize_2 = Notarize::read(reader)?;
2097
2098        if notarize_1.signer() != notarize_2.signer() || notarize_1.round() != notarize_2.round() {
2099            return Err(Error::Invalid(
2100                "consensus::simplex::ConflictingNotarize",
2101                "invalid conflicting notarize",
2102            ));
2103        }
2104
2105        Ok(ConflictingNotarize {
2106            notarize_1,
2107            notarize_2,
2108        })
2109    }
2110}
2111
2112impl<S: Scheme, D: Digest> EncodeSize for ConflictingNotarize<S, D> {
2113    fn encode_size(&self) -> usize {
2114        self.notarize_1.encode_size() + self.notarize_2.encode_size()
2115    }
2116}
2117
2118/// ConflictingFinalize represents evidence of a Byzantine validator sending conflicting finalizes.
2119/// Similar to ConflictingNotarize, but for finalizes.
2120#[derive(Clone, Debug)]
2121pub struct ConflictingFinalize<S: Scheme, D: Digest> {
2122    /// The second conflicting finalize
2123    finalize_1: Finalize<S, D>,
2124    /// The second conflicting finalize
2125    finalize_2: Finalize<S, D>,
2126}
2127
2128impl<S: Scheme, D: Digest> PartialEq for ConflictingFinalize<S, D> {
2129    fn eq(&self, other: &Self) -> bool {
2130        self.finalize_1 == other.finalize_1 && self.finalize_2 == other.finalize_2
2131    }
2132}
2133
2134impl<S: Scheme, D: Digest> Eq for ConflictingFinalize<S, D> {}
2135
2136impl<S: Scheme, D: Digest> Hash for ConflictingFinalize<S, D> {
2137    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
2138        self.finalize_1.hash(state);
2139        self.finalize_2.hash(state);
2140    }
2141}
2142
2143impl<S: Scheme, D: Digest> ConflictingFinalize<S, D> {
2144    /// Creates a new conflicting finalize evidence from two conflicting finalizes.
2145    pub fn new(finalize_1: Finalize<S, D>, finalize_2: Finalize<S, D>) -> Self {
2146        assert_eq!(finalize_1.round(), finalize_2.round());
2147        assert_eq!(finalize_1.signer(), finalize_2.signer());
2148
2149        ConflictingFinalize {
2150            finalize_1,
2151            finalize_2,
2152        }
2153    }
2154
2155    /// Verifies that both conflicting signatures are valid, proving Byzantine behavior.
2156    pub fn verify(&self, scheme: &S, namespace: &[u8]) -> bool {
2157        self.finalize_1.verify(scheme, namespace) && self.finalize_2.verify(scheme, namespace)
2158    }
2159}
2160
2161impl<S: Scheme, D: Digest> Attributable for ConflictingFinalize<S, D> {
2162    fn signer(&self) -> u32 {
2163        self.finalize_1.signer()
2164    }
2165}
2166
2167impl<S: Scheme, D: Digest> Epochable for ConflictingFinalize<S, D> {
2168    type Epoch = Epoch;
2169
2170    fn epoch(&self) -> Epoch {
2171        self.finalize_1.epoch()
2172    }
2173}
2174
2175impl<S: Scheme, D: Digest> Viewable for ConflictingFinalize<S, D> {
2176    type View = View;
2177
2178    fn view(&self) -> View {
2179        self.finalize_1.view()
2180    }
2181}
2182
2183impl<S: Scheme, D: Digest> Write for ConflictingFinalize<S, D> {
2184    fn write(&self, writer: &mut impl BufMut) {
2185        self.finalize_1.write(writer);
2186        self.finalize_2.write(writer);
2187    }
2188}
2189
2190impl<S: Scheme, D: Digest> Read for ConflictingFinalize<S, D> {
2191    type Cfg = ();
2192
2193    fn read_cfg(reader: &mut impl Buf, _: &()) -> Result<Self, Error> {
2194        let finalize_1 = Finalize::read(reader)?;
2195        let finalize_2 = Finalize::read(reader)?;
2196
2197        if finalize_1.signer() != finalize_2.signer() || finalize_1.round() != finalize_2.round() {
2198            return Err(Error::Invalid(
2199                "consensus::simplex::ConflictingFinalize",
2200                "invalid conflicting finalize",
2201            ));
2202        }
2203
2204        Ok(ConflictingFinalize {
2205            finalize_1,
2206            finalize_2,
2207        })
2208    }
2209}
2210
2211impl<S: Scheme, D: Digest> EncodeSize for ConflictingFinalize<S, D> {
2212    fn encode_size(&self) -> usize {
2213        self.finalize_1.encode_size() + self.finalize_2.encode_size()
2214    }
2215}
2216
2217/// NullifyFinalize represents evidence of a Byzantine validator sending both a nullify and finalize
2218/// for the same view, which is contradictory behavior (a validator should either try to skip a view OR
2219/// finalize a proposal, not both).
2220#[derive(Clone, Debug)]
2221pub struct NullifyFinalize<S: Scheme, D: Digest> {
2222    /// The conflicting nullify
2223    nullify: Nullify<S>,
2224    /// The conflicting finalize
2225    finalize: Finalize<S, D>,
2226}
2227
2228impl<S: Scheme, D: Digest> PartialEq for NullifyFinalize<S, D> {
2229    fn eq(&self, other: &Self) -> bool {
2230        self.nullify == other.nullify && self.finalize == other.finalize
2231    }
2232}
2233
2234impl<S: Scheme, D: Digest> Eq for NullifyFinalize<S, D> {}
2235
2236impl<S: Scheme, D: Digest> Hash for NullifyFinalize<S, D> {
2237    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
2238        self.nullify.hash(state);
2239        self.finalize.hash(state);
2240    }
2241}
2242
2243impl<S: Scheme, D: Digest> NullifyFinalize<S, D> {
2244    /// Creates a new nullify-finalize evidence from a nullify and a finalize.
2245    pub fn new(nullify: Nullify<S>, finalize: Finalize<S, D>) -> Self {
2246        assert_eq!(nullify.round, finalize.round());
2247        assert_eq!(nullify.signer(), finalize.signer());
2248
2249        NullifyFinalize { nullify, finalize }
2250    }
2251
2252    /// Verifies that both the nullify and finalize signatures are valid, proving Byzantine behavior.
2253    pub fn verify(&self, scheme: &S, namespace: &[u8]) -> bool {
2254        self.nullify.verify::<D>(scheme, namespace) && self.finalize.verify(scheme, namespace)
2255    }
2256}
2257
2258impl<S: Scheme, D: Digest> Attributable for NullifyFinalize<S, D> {
2259    fn signer(&self) -> u32 {
2260        self.nullify.signer()
2261    }
2262}
2263
2264impl<S: Scheme, D: Digest> Epochable for NullifyFinalize<S, D> {
2265    type Epoch = Epoch;
2266
2267    fn epoch(&self) -> Epoch {
2268        self.nullify.epoch()
2269    }
2270}
2271
2272impl<S: Scheme, D: Digest> Viewable for NullifyFinalize<S, D> {
2273    type View = View;
2274
2275    fn view(&self) -> View {
2276        self.nullify.view()
2277    }
2278}
2279
2280impl<S: Scheme, D: Digest> Write for NullifyFinalize<S, D> {
2281    fn write(&self, writer: &mut impl BufMut) {
2282        self.nullify.write(writer);
2283        self.finalize.write(writer);
2284    }
2285}
2286
2287impl<S: Scheme, D: Digest> Read for NullifyFinalize<S, D> {
2288    type Cfg = ();
2289
2290    fn read_cfg(reader: &mut impl Buf, _: &()) -> Result<Self, Error> {
2291        let nullify = Nullify::read(reader)?;
2292        let finalize = Finalize::read(reader)?;
2293
2294        if nullify.signer() != finalize.signer() || nullify.round != finalize.round() {
2295            return Err(Error::Invalid(
2296                "consensus::simplex::NullifyFinalize",
2297                "mismatched signatures",
2298            ));
2299        }
2300
2301        Ok(NullifyFinalize { nullify, finalize })
2302    }
2303}
2304
2305impl<S: Scheme, D: Digest> EncodeSize for NullifyFinalize<S, D> {
2306    fn encode_size(&self) -> usize {
2307        self.nullify.encode_size() + self.finalize.encode_size()
2308    }
2309}
2310
2311#[cfg(test)]
2312mod tests {
2313    use super::*;
2314    use crate::simplex::signing_scheme::{bls12381_threshold, ed25519};
2315    use commonware_codec::{Decode, DecodeExt, Encode};
2316    use commonware_cryptography::{
2317        bls12381::{
2318            dkg::ops::{self},
2319            primitives::variant::MinSig,
2320        },
2321        ed25519::{PrivateKey as EdPrivateKey, PublicKey as EdPublicKey},
2322        sha256::Digest as Sha256,
2323        PrivateKeyExt, Signer,
2324    };
2325    use commonware_utils::quorum;
2326    use rand::{
2327        rngs::{OsRng, StdRng},
2328        SeedableRng,
2329    };
2330
2331    const NAMESPACE: &[u8] = b"test";
2332
2333    // Helper function to create a sample digest
2334    fn sample_digest(v: u8) -> Sha256 {
2335        Sha256::from([v; 32]) // Simple fixed digest for testing
2336    }
2337
2338    fn generate_bls12381_threshold_schemes(
2339        n: u32,
2340        seed: u64,
2341    ) -> Vec<bls12381_threshold::Scheme<EdPublicKey, MinSig>> {
2342        let mut rng = StdRng::seed_from_u64(seed);
2343        let t = quorum(n);
2344
2345        // Generate ed25519 keys for participant identities
2346        let participants: Vec<_> = (0..n)
2347            .map(|_| EdPrivateKey::from_rng(&mut rng).public_key())
2348            .collect();
2349        let (polynomial, shares) = ops::generate_shares::<_, MinSig>(&mut rng, None, n, t);
2350
2351        shares
2352            .into_iter()
2353            .map(|share| {
2354                bls12381_threshold::Scheme::new(participants.clone().into(), &polynomial, share)
2355            })
2356            .collect()
2357    }
2358
2359    fn generate_bls12381_threshold_verifier(
2360        n: u32,
2361        seed: u64,
2362    ) -> bls12381_threshold::Scheme<EdPublicKey, MinSig> {
2363        let mut rng = StdRng::seed_from_u64(seed);
2364        let t = quorum(n);
2365
2366        // Generate ed25519 keys for participant identities
2367        let participants: Vec<_> = (0..n)
2368            .map(|_| EdPrivateKey::from_rng(&mut rng).public_key())
2369            .collect();
2370
2371        let (polynomial, _) = ops::generate_shares::<_, MinSig>(&mut rng, None, n, t);
2372        bls12381_threshold::Scheme::verifier(participants.into(), &polynomial)
2373    }
2374
2375    fn generate_ed25519_schemes(n: usize, seed: u64) -> Vec<ed25519::Scheme> {
2376        let mut rng = StdRng::seed_from_u64(seed);
2377        let private_keys: Vec<_> = (0..n).map(|_| EdPrivateKey::from_rng(&mut rng)).collect();
2378
2379        let participants: Ordered<_> = private_keys.iter().map(|p| p.public_key()).collect();
2380
2381        private_keys
2382            .into_iter()
2383            .map(|sk| ed25519::Scheme::new(participants.clone(), sk))
2384            .collect()
2385    }
2386
2387    #[test]
2388    fn test_proposal_encode_decode() {
2389        let proposal = Proposal::new(Round::new(0, 10), 5, sample_digest(1));
2390        let encoded = proposal.encode();
2391        let decoded = Proposal::<Sha256>::decode(encoded).unwrap();
2392        assert_eq!(proposal, decoded);
2393    }
2394
2395    fn notarize_encode_decode<S: Scheme>(schemes: &[S]) {
2396        let round = Round::new(0, 10);
2397        let proposal = Proposal::new(round, 5, sample_digest(1));
2398        let notarize = Notarize::sign(&schemes[0], NAMESPACE, proposal).unwrap();
2399
2400        let encoded = notarize.encode();
2401        let decoded = Notarize::decode(encoded).unwrap();
2402
2403        assert_eq!(notarize, decoded);
2404        assert!(decoded.verify(&schemes[0], NAMESPACE));
2405    }
2406
2407    #[test]
2408    fn test_notarize_encode_decode() {
2409        let bls_threshold_schemes = generate_bls12381_threshold_schemes(5, 0);
2410        notarize_encode_decode(&bls_threshold_schemes);
2411
2412        let ed_schemes = generate_ed25519_schemes(5, 0);
2413        notarize_encode_decode(&ed_schemes);
2414    }
2415
2416    fn notarization_encode_decode<S: Scheme>(schemes: &[S]) {
2417        let proposal = Proposal::new(Round::new(0, 10), 5, sample_digest(1));
2418        let notarizes: Vec<_> = schemes
2419            .iter()
2420            .map(|scheme| Notarize::sign(scheme, NAMESPACE, proposal.clone()).unwrap())
2421            .collect();
2422        let notarization = Notarization::from_notarizes(&schemes[0], &notarizes).unwrap();
2423        let encoded = notarization.encode();
2424        let cfg = schemes[0].certificate_codec_config();
2425        let decoded = Notarization::decode_cfg(encoded, &cfg).unwrap();
2426        assert_eq!(notarization, decoded);
2427        assert!(decoded.verify(&mut OsRng, &schemes[0], NAMESPACE));
2428    }
2429
2430    #[test]
2431    fn test_notarization_encode_decode() {
2432        let bls_threshold_schemes = generate_bls12381_threshold_schemes(5, 1);
2433        notarization_encode_decode(&bls_threshold_schemes);
2434
2435        let ed_schemes = generate_ed25519_schemes(5, 1);
2436        notarization_encode_decode(&ed_schemes);
2437    }
2438
2439    fn nullify_encode_decode<S: Scheme>(schemes: &[S]) {
2440        let round = Round::new(0, 10);
2441        let nullify = Nullify::sign::<Sha256>(&schemes[0], NAMESPACE, round).unwrap();
2442        let encoded = nullify.encode();
2443        let decoded = Nullify::decode(encoded).unwrap();
2444        assert_eq!(nullify, decoded);
2445        assert!(decoded.verify::<Sha256>(&schemes[0], NAMESPACE));
2446    }
2447
2448    #[test]
2449    fn test_nullify_encode_decode() {
2450        let bls_threshold_schemes = generate_bls12381_threshold_schemes(5, 2);
2451        nullify_encode_decode(&bls_threshold_schemes);
2452
2453        let ed_schemes = generate_ed25519_schemes(5, 2);
2454        nullify_encode_decode(&ed_schemes);
2455    }
2456
2457    fn nullification_encode_decode<S: Scheme>(schemes: &[S]) {
2458        let round = Round::new(333, 10);
2459        let nullifies: Vec<_> = schemes
2460            .iter()
2461            .map(|scheme| Nullify::sign::<Sha256>(scheme, NAMESPACE, round).unwrap())
2462            .collect();
2463        let nullification = Nullification::from_nullifies(&schemes[0], &nullifies).unwrap();
2464        let encoded = nullification.encode();
2465        let cfg = schemes[0].certificate_codec_config();
2466        let decoded = Nullification::decode_cfg(encoded, &cfg).unwrap();
2467        assert_eq!(nullification, decoded);
2468        assert!(decoded.verify::<_, Sha256>(&mut OsRng, &schemes[0], NAMESPACE));
2469    }
2470
2471    #[test]
2472    fn test_nullification_encode_decode() {
2473        let bls_threshold_schemes = generate_bls12381_threshold_schemes(5, 3);
2474        nullification_encode_decode(&bls_threshold_schemes);
2475
2476        let ed_schemes = generate_ed25519_schemes(5, 3);
2477        nullification_encode_decode(&ed_schemes);
2478    }
2479
2480    fn finalize_encode_decode<S: Scheme>(schemes: &[S]) {
2481        let round = Round::new(0, 10);
2482        let proposal = Proposal::new(round, 5, sample_digest(1));
2483        let finalize = Finalize::sign(&schemes[0], NAMESPACE, proposal).unwrap();
2484        let encoded = finalize.encode();
2485        let decoded = Finalize::decode(encoded).unwrap();
2486        assert_eq!(finalize, decoded);
2487        assert!(decoded.verify(&schemes[0], NAMESPACE));
2488    }
2489
2490    #[test]
2491    fn test_finalize_encode_decode() {
2492        let bls_threshold_schemes = generate_bls12381_threshold_schemes(5, 4);
2493        finalize_encode_decode(&bls_threshold_schemes);
2494
2495        let ed_schemes = generate_ed25519_schemes(5, 4);
2496        finalize_encode_decode(&ed_schemes);
2497    }
2498
2499    fn finalization_encode_decode<S: Scheme>(schemes: &[S]) {
2500        let round = Round::new(0, 10);
2501        let proposal = Proposal::new(round, 5, sample_digest(1));
2502        let finalizes: Vec<_> = schemes
2503            .iter()
2504            .map(|scheme| Finalize::sign(scheme, NAMESPACE, proposal.clone()).unwrap())
2505            .collect();
2506        let finalization = Finalization::from_finalizes(&schemes[0], &finalizes).unwrap();
2507        let encoded = finalization.encode();
2508        let cfg = schemes[0].certificate_codec_config();
2509        let decoded = Finalization::decode_cfg(encoded, &cfg).unwrap();
2510        assert_eq!(finalization, decoded);
2511        assert!(decoded.verify(&mut OsRng, &schemes[0], NAMESPACE));
2512    }
2513
2514    #[test]
2515    fn test_finalization_encode_decode() {
2516        let bls_threshold_schemes = generate_bls12381_threshold_schemes(5, 5);
2517        finalization_encode_decode(&bls_threshold_schemes);
2518
2519        let ed_schemes = generate_ed25519_schemes(5, 5);
2520        finalization_encode_decode(&ed_schemes);
2521    }
2522
2523    fn backfiller_encode_decode<S: Scheme>(schemes: &[S]) {
2524        let cfg = schemes[0].certificate_codec_config();
2525        let request = Request::new(1, vec![10, 11], vec![12, 13]);
2526        let encoded_request = Backfiller::<S, Sha256>::Request(request.clone()).encode();
2527        let decoded_request =
2528            Backfiller::<S, Sha256>::decode_cfg(encoded_request, &(usize::MAX, cfg.clone()))
2529                .unwrap();
2530        assert!(matches!(decoded_request, Backfiller::Request(r) if r == request));
2531
2532        let round = Round::new(0, 10);
2533        let proposal = Proposal::new(round, 5, sample_digest(1));
2534        let notarizes: Vec<_> = schemes
2535            .iter()
2536            .map(|scheme| Notarize::sign(scheme, NAMESPACE, proposal.clone()).unwrap())
2537            .collect();
2538        let notarization = Notarization::from_notarizes(&schemes[0], &notarizes).unwrap();
2539
2540        let nullifies: Vec<_> = schemes
2541            .iter()
2542            .map(|scheme| Nullify::sign::<Sha256>(scheme, NAMESPACE, round).unwrap())
2543            .collect();
2544        let nullification = Nullification::from_nullifies(&schemes[0], &nullifies).unwrap();
2545
2546        let response = Response::<S, Sha256>::new(1, vec![notarization], vec![nullification]);
2547        let encoded_response = Backfiller::<S, Sha256>::Response(response.clone()).encode();
2548        let decoded_response =
2549            Backfiller::<S, Sha256>::decode_cfg(encoded_response, &(usize::MAX, cfg)).unwrap();
2550        assert!(matches!(decoded_response, Backfiller::Response(r) if r.id == response.id));
2551    }
2552
2553    #[test]
2554    fn test_backfiller_encode_decode() {
2555        let bls_threshold_schemes = generate_bls12381_threshold_schemes(5, 6);
2556        backfiller_encode_decode(&bls_threshold_schemes);
2557
2558        let ed_schemes = generate_ed25519_schemes(5, 6);
2559        backfiller_encode_decode(&ed_schemes);
2560    }
2561
2562    #[test]
2563    fn test_request_encode_decode() {
2564        let request = Request::new(1, vec![10, 11], vec![12, 13]);
2565        let encoded = request.encode();
2566        let decoded = Request::decode_cfg(encoded, &usize::MAX).unwrap();
2567        assert_eq!(request, decoded);
2568    }
2569
2570    fn response_encode_decode<S: Scheme>(schemes: &[S]) {
2571        let round = Round::new(0, 10);
2572        let proposal = Proposal::new(round, 5, sample_digest(1));
2573
2574        let notarizes: Vec<_> = schemes
2575            .iter()
2576            .map(|scheme| Notarize::sign(scheme, NAMESPACE, proposal.clone()).unwrap())
2577            .collect();
2578        let notarization = Notarization::from_notarizes(&schemes[0], &notarizes).unwrap();
2579
2580        let nullifies: Vec<_> = schemes
2581            .iter()
2582            .map(|scheme| Nullify::sign::<Sha256>(scheme, NAMESPACE, round).unwrap())
2583            .collect();
2584        let nullification = Nullification::from_nullifies(&schemes[0], &nullifies).unwrap();
2585
2586        let response = Response::<S, Sha256>::new(1, vec![notarization], vec![nullification]);
2587        let cfg = schemes[0].certificate_codec_config();
2588        let mut decoded =
2589            Response::<S, Sha256>::decode_cfg(response.encode(), &(usize::MAX, cfg.clone()))
2590                .unwrap();
2591        assert_eq!(response.id, decoded.id);
2592        assert_eq!(response.notarizations.len(), decoded.notarizations.len());
2593        assert_eq!(response.nullifications.len(), decoded.nullifications.len());
2594
2595        let mut rng = OsRng;
2596        assert!(decoded.verify(&mut rng, &schemes[0], NAMESPACE));
2597
2598        decoded.nullifications[0].round = Round::new(
2599            decoded.nullifications[0].round.epoch(),
2600            decoded.nullifications[0].round.view() + 1,
2601        );
2602        assert!(!decoded.verify(&mut rng, &schemes[0], NAMESPACE));
2603    }
2604
2605    #[test]
2606    fn test_response_encode_decode() {
2607        let bls_threshold_schemes = generate_bls12381_threshold_schemes(5, 7);
2608        response_encode_decode(&bls_threshold_schemes);
2609
2610        let ed_schemes = generate_ed25519_schemes(5, 7);
2611        response_encode_decode(&ed_schemes);
2612    }
2613
2614    fn conflicting_notarize_encode_decode<S: Scheme>(schemes: &[S]) {
2615        let proposal1 = Proposal::new(Round::new(0, 10), 5, sample_digest(1));
2616        let proposal2 = Proposal::new(Round::new(0, 10), 5, sample_digest(2));
2617        let notarize1 = Notarize::sign(&schemes[0], NAMESPACE, proposal1).unwrap();
2618        let notarize2 = Notarize::sign(&schemes[0], NAMESPACE, proposal2).unwrap();
2619        let conflicting = ConflictingNotarize::new(notarize1, notarize2);
2620
2621        let encoded = conflicting.encode();
2622        let decoded = ConflictingNotarize::<S, Sha256>::decode(encoded).unwrap();
2623
2624        assert_eq!(conflicting, decoded);
2625        assert!(decoded.verify(&schemes[0], NAMESPACE));
2626    }
2627
2628    #[test]
2629    fn test_conflicting_notarize_encode_decode() {
2630        let bls_threshold_schemes = generate_bls12381_threshold_schemes(5, 8);
2631        conflicting_notarize_encode_decode(&bls_threshold_schemes);
2632
2633        let ed_schemes = generate_ed25519_schemes(5, 8);
2634        conflicting_notarize_encode_decode(&ed_schemes);
2635    }
2636
2637    fn conflicting_finalize_encode_decode<S: Scheme>(schemes: &[S]) {
2638        let proposal1 = Proposal::new(Round::new(0, 10), 5, sample_digest(1));
2639        let proposal2 = Proposal::new(Round::new(0, 10), 5, sample_digest(2));
2640        let finalize1 = Finalize::sign(&schemes[0], NAMESPACE, proposal1).unwrap();
2641        let finalize2 = Finalize::sign(&schemes[0], NAMESPACE, proposal2).unwrap();
2642        let conflicting = ConflictingFinalize::new(finalize1, finalize2);
2643
2644        let encoded = conflicting.encode();
2645        let decoded = ConflictingFinalize::<S, Sha256>::decode(encoded).unwrap();
2646
2647        assert_eq!(conflicting, decoded);
2648        assert!(decoded.verify(&schemes[0], NAMESPACE));
2649    }
2650
2651    #[test]
2652    fn test_conflicting_finalize_encode_decode() {
2653        let bls_threshold_schemes = generate_bls12381_threshold_schemes(5, 9);
2654        conflicting_finalize_encode_decode(&bls_threshold_schemes);
2655
2656        let ed_schemes = generate_ed25519_schemes(5, 9);
2657        conflicting_finalize_encode_decode(&ed_schemes);
2658    }
2659
2660    fn nullify_finalize_encode_decode<S: Scheme>(schemes: &[S]) {
2661        let round = Round::new(0, 10);
2662        let proposal = Proposal::new(round, 5, sample_digest(1));
2663        let nullify = Nullify::sign::<Sha256>(&schemes[0], NAMESPACE, round).unwrap();
2664        let finalize = Finalize::sign(&schemes[0], NAMESPACE, proposal).unwrap();
2665        let conflict = NullifyFinalize::new(nullify, finalize);
2666
2667        let encoded = conflict.encode();
2668        let decoded = NullifyFinalize::<S, Sha256>::decode(encoded).unwrap();
2669
2670        assert_eq!(conflict, decoded);
2671        assert!(decoded.verify(&schemes[0], NAMESPACE));
2672    }
2673
2674    #[test]
2675    fn test_nullify_finalize_encode_decode() {
2676        let bls_threshold_schemes = generate_bls12381_threshold_schemes(5, 10);
2677        nullify_finalize_encode_decode(&bls_threshold_schemes);
2678
2679        let ed_schemes = generate_ed25519_schemes(5, 10);
2680        nullify_finalize_encode_decode(&ed_schemes);
2681    }
2682
2683    fn notarize_verify_wrong_namespace<S: Scheme>(scheme: &S) {
2684        let round = Round::new(0, 10);
2685        let proposal = Proposal::new(round, 5, sample_digest(1));
2686        let notarize = Notarize::sign(scheme, NAMESPACE, proposal).unwrap();
2687
2688        assert!(notarize.verify(scheme, NAMESPACE));
2689        assert!(!notarize.verify(scheme, b"wrong_namespace"));
2690    }
2691
2692    #[test]
2693    fn test_notarize_verify_wrong_namespace() {
2694        let bls_threshold_schemes = generate_bls12381_threshold_schemes(5, 220);
2695        notarize_verify_wrong_namespace(&bls_threshold_schemes[0]);
2696
2697        let ed_schemes = generate_ed25519_schemes(5, 220);
2698        notarize_verify_wrong_namespace(&ed_schemes[0]);
2699    }
2700
2701    fn notarize_verify_wrong_scheme<S: Scheme>(scheme: &S, wrong_scheme: &S) {
2702        let round = Round::new(0, 10);
2703        let proposal = Proposal::new(round, 5, sample_digest(2));
2704        let notarize = Notarize::sign(scheme, NAMESPACE, proposal).unwrap();
2705
2706        assert!(notarize.verify(scheme, NAMESPACE));
2707        assert!(!notarize.verify(wrong_scheme, NAMESPACE));
2708    }
2709
2710    #[test]
2711    fn test_notarize_verify_wrong_scheme() {
2712        let bls_threshold_schemes = generate_bls12381_threshold_schemes(5, 221);
2713        let bls_threshold_wrong_scheme = generate_bls12381_threshold_verifier(5, 501);
2714        notarize_verify_wrong_scheme(&bls_threshold_schemes[0], &bls_threshold_wrong_scheme);
2715
2716        let ed_schemes = generate_ed25519_schemes(5, 221);
2717        let ed_wrong_scheme = generate_ed25519_schemes(5, 321);
2718        notarize_verify_wrong_scheme(&ed_schemes[0], &ed_wrong_scheme[0]);
2719    }
2720
2721    fn notarization_verify_wrong_scheme<S: Scheme>(schemes: &[S], wrong_scheme: &S) {
2722        let round = Round::new(0, 10);
2723        let proposal = Proposal::new(round, 5, sample_digest(3));
2724        let quorum = quorum(schemes.len() as u32);
2725        let notarizes: Vec<_> = schemes
2726            .iter()
2727            .take(quorum as usize)
2728            .map(|scheme| Notarize::sign(scheme, NAMESPACE, proposal.clone()).unwrap())
2729            .collect();
2730
2731        let notarization =
2732            Notarization::from_notarizes(&schemes[0], &notarizes).expect("quorum notarization");
2733        let mut rng = OsRng;
2734        assert!(notarization.verify(&mut rng, &schemes[0], NAMESPACE));
2735
2736        let mut rng = OsRng;
2737        assert!(!notarization.verify(&mut rng, wrong_scheme, NAMESPACE));
2738    }
2739
2740    #[test]
2741    fn test_notarization_verify_wrong_scheme() {
2742        let bls_threshold_schemes = generate_bls12381_threshold_schemes(5, 222);
2743        let bls_threshold_wrong_scheme = generate_bls12381_threshold_verifier(5, 502);
2744        notarization_verify_wrong_scheme(&bls_threshold_schemes, &bls_threshold_wrong_scheme);
2745
2746        let ed_schemes = generate_ed25519_schemes(5, 222);
2747        let ed_wrong_scheme = generate_ed25519_schemes(5, 422);
2748        notarization_verify_wrong_scheme(&ed_schemes, &ed_wrong_scheme[0]);
2749    }
2750
2751    fn notarization_verify_wrong_namespace<S: Scheme>(schemes: &[S]) {
2752        let round = Round::new(0, 10);
2753        let proposal = Proposal::new(round, 5, sample_digest(4));
2754        let quorum = quorum(schemes.len() as u32);
2755        let notarizes: Vec<_> = schemes
2756            .iter()
2757            .take(quorum as usize)
2758            .map(|scheme| Notarize::sign(scheme, NAMESPACE, proposal.clone()).unwrap())
2759            .collect();
2760
2761        let notarization =
2762            Notarization::from_notarizes(&schemes[0], &notarizes).expect("quorum notarization");
2763        let mut rng = OsRng;
2764        assert!(notarization.verify(&mut rng, &schemes[0], NAMESPACE));
2765
2766        let mut rng = OsRng;
2767        assert!(!notarization.verify(&mut rng, &schemes[0], b"wrong_namespace"));
2768    }
2769
2770    #[test]
2771    fn test_notarization_verify_wrong_namespace() {
2772        let bls_threshold_schemes = generate_bls12381_threshold_schemes(5, 223);
2773        notarization_verify_wrong_namespace(&bls_threshold_schemes);
2774
2775        let ed_schemes = generate_ed25519_schemes(5, 223);
2776        notarization_verify_wrong_namespace(&ed_schemes);
2777    }
2778
2779    fn notarization_recover_insufficient_signatures<S: Scheme>(schemes: &[S]) {
2780        let quorum = quorum(schemes.len() as u32);
2781        assert!(quorum > 1, "test requires quorum larger than one");
2782        let round = Round::new(0, 10);
2783        let proposal = Proposal::new(round, 5, sample_digest(5));
2784        let notarizes: Vec<_> = schemes
2785            .iter()
2786            .take((quorum - 1) as usize)
2787            .map(|scheme| Notarize::sign(scheme, NAMESPACE, proposal.clone()).unwrap())
2788            .collect();
2789
2790        assert!(
2791            Notarization::from_notarizes(&schemes[0], &notarizes).is_none(),
2792            "insufficient votes should not form a notarization"
2793        );
2794    }
2795
2796    #[test]
2797    fn test_notarization_recover_insufficient_signatures() {
2798        let bls_threshold_schemes = generate_bls12381_threshold_schemes(5, 224);
2799        notarization_recover_insufficient_signatures(&bls_threshold_schemes);
2800
2801        let ed_schemes = generate_ed25519_schemes(5, 224);
2802        notarization_recover_insufficient_signatures(&ed_schemes);
2803    }
2804
2805    fn conflicting_notarize_detection<S: Scheme>(scheme: &S, wrong_scheme: &S) {
2806        let round = Round::new(0, 10);
2807        let proposal1 = Proposal::new(round, 5, sample_digest(6));
2808        let proposal2 = Proposal::new(round, 5, sample_digest(7));
2809
2810        let notarize1 = Notarize::sign(scheme, NAMESPACE, proposal1).unwrap();
2811        let notarize2 = Notarize::sign(scheme, NAMESPACE, proposal2).unwrap();
2812        let conflict = ConflictingNotarize::new(notarize1, notarize2);
2813
2814        assert!(conflict.verify(scheme, NAMESPACE));
2815        assert!(!conflict.verify(scheme, b"wrong_namespace"));
2816        assert!(!conflict.verify(wrong_scheme, NAMESPACE));
2817    }
2818
2819    #[test]
2820    fn test_conflicting_notarize_detection() {
2821        let bls_threshold_schemes = generate_bls12381_threshold_schemes(5, 225);
2822        let bls_threshold_wrong_scheme = generate_bls12381_threshold_verifier(5, 503);
2823        conflicting_notarize_detection(&bls_threshold_schemes[0], &bls_threshold_wrong_scheme);
2824
2825        let ed_schemes = generate_ed25519_schemes(5, 225);
2826        let ed_wrong_scheme = generate_ed25519_schemes(5, 425);
2827        conflicting_notarize_detection(&ed_schemes[0], &ed_wrong_scheme[0]);
2828    }
2829
2830    fn nullify_finalize_detection<S: Scheme>(scheme: &S, wrong_scheme: &S) {
2831        let round = Round::new(0, 10);
2832        let proposal = Proposal::new(round, 5, sample_digest(8));
2833
2834        let nullify = Nullify::sign::<Sha256>(scheme, NAMESPACE, round).unwrap();
2835        let finalize = Finalize::sign(scheme, NAMESPACE, proposal).unwrap();
2836        let conflict = NullifyFinalize::new(nullify, finalize);
2837
2838        assert!(conflict.verify(scheme, NAMESPACE));
2839        assert!(!conflict.verify(scheme, b"wrong_namespace"));
2840        assert!(!conflict.verify(wrong_scheme, NAMESPACE));
2841    }
2842
2843    #[test]
2844    fn test_nullify_finalize_detection() {
2845        let bls_threshold_schemes = generate_bls12381_threshold_schemes(5, 226);
2846        let bls_threshold_wrong_scheme = generate_bls12381_threshold_verifier(5, 504);
2847        nullify_finalize_detection(&bls_threshold_schemes[0], &bls_threshold_wrong_scheme);
2848
2849        let ed_schemes = generate_ed25519_schemes(5, 226);
2850        let ed_wrong_scheme = generate_ed25519_schemes(5, 426);
2851        nullify_finalize_detection(&ed_schemes[0], &ed_wrong_scheme[0]);
2852    }
2853
2854    fn finalization_verify_wrong_scheme<S: Scheme>(schemes: &[S], wrong_scheme: &S) {
2855        let round = Round::new(0, 10);
2856        let proposal = Proposal::new(round, 5, sample_digest(9));
2857        let quorum = quorum(schemes.len() as u32);
2858        let finalizes: Vec<_> = schemes
2859            .iter()
2860            .take(quorum as usize)
2861            .map(|scheme| Finalize::sign(scheme, NAMESPACE, proposal.clone()).unwrap())
2862            .collect();
2863
2864        let finalization =
2865            Finalization::from_finalizes(&schemes[0], &finalizes).expect("quorum finalization");
2866        let mut rng = OsRng;
2867        assert!(finalization.verify(&mut rng, &schemes[0], NAMESPACE));
2868
2869        let mut rng = OsRng;
2870        assert!(!finalization.verify(&mut rng, wrong_scheme, NAMESPACE));
2871    }
2872
2873    #[test]
2874    fn test_finalization_wrong_scheme() {
2875        let bls_threshold_schemes = generate_bls12381_threshold_schemes(5, 227);
2876        let bls_threshold_wrong_scheme = generate_bls12381_threshold_verifier(5, 505);
2877        finalization_verify_wrong_scheme(&bls_threshold_schemes, &bls_threshold_wrong_scheme);
2878
2879        let ed_schemes = generate_ed25519_schemes(5, 227);
2880        let ed_wrong_scheme = generate_ed25519_schemes(5, 427);
2881        finalization_verify_wrong_scheme(&ed_schemes, &ed_wrong_scheme[0]);
2882    }
2883
2884    // Helper to create a Notarize message for any signing scheme
2885    fn create_notarize<S: Scheme>(
2886        scheme: &S,
2887        round: Round,
2888        parent_view: View,
2889        payload_val: u8,
2890    ) -> Notarize<S, Sha256> {
2891        let proposal = Proposal::new(round, parent_view, sample_digest(payload_val));
2892        Notarize::sign(scheme, NAMESPACE, proposal).unwrap()
2893    }
2894
2895    // Helper to create a Nullify message for any signing scheme
2896    #[allow(dead_code)]
2897    fn create_nullify<S: Scheme>(scheme: &S, round: Round) -> Nullify<S> {
2898        Nullify::sign::<Sha256>(scheme, NAMESPACE, round).unwrap()
2899    }
2900
2901    // Helper to create a Finalize message for any signing scheme
2902    #[allow(dead_code)]
2903    fn create_finalize<S: Scheme>(
2904        scheme: &S,
2905        round: Round,
2906        parent_view: View,
2907        payload_val: u8,
2908    ) -> Finalize<S, Sha256> {
2909        let proposal = Proposal::new(round, parent_view, sample_digest(payload_val));
2910        Finalize::sign(scheme, NAMESPACE, proposal).unwrap()
2911    }
2912
2913    fn create_notarization<S: Scheme>(
2914        schemes: &[S],
2915        round: Round,
2916        parent_view: View,
2917        payload_val: u8,
2918        quorum: u32,
2919    ) -> Notarization<S, Sha256> {
2920        let proposal = Proposal::new(round, parent_view, sample_digest(payload_val));
2921        let notarizes: Vec<_> = schemes
2922            .iter()
2923            .take(quorum as usize)
2924            .map(|scheme| Notarize::sign(scheme, NAMESPACE, proposal.clone()).unwrap())
2925            .collect();
2926        Notarization::from_notarizes(&schemes[0], &notarizes).unwrap()
2927    }
2928
2929    fn batch_verifier_add_notarize<S: Scheme + Clone>(schemes: Vec<S>) {
2930        let quorum = quorum(schemes.len() as u32);
2931        let mut verifier = BatchVerifier::<S, Sha256>::new(schemes[0].clone(), Some(quorum));
2932
2933        let round = Round::new(0, 1);
2934        let notarize1 = create_notarize(&schemes[0], round, 0, 1);
2935        let notarize2 = create_notarize(&schemes[1], round, 0, 1);
2936        let notarize_diff = create_notarize(&schemes[2], round, 0, 2);
2937
2938        verifier.add(Voter::Notarize(notarize1.clone()), false);
2939        assert_eq!(verifier.notarizes.len(), 1);
2940        assert_eq!(verifier.notarizes_verified, 0);
2941
2942        verifier.add(Voter::Notarize(notarize1.clone()), true);
2943        assert_eq!(verifier.notarizes.len(), 1);
2944        assert_eq!(verifier.notarizes_verified, 1);
2945
2946        verifier.set_leader(notarize1.signer());
2947        assert!(verifier.leader_proposal.is_some());
2948        assert_eq!(
2949            verifier.leader_proposal.as_ref().unwrap(),
2950            &notarize1.proposal
2951        );
2952        assert!(verifier.notarizes_force);
2953        assert_eq!(verifier.notarizes.len(), 1);
2954
2955        verifier.add(Voter::Notarize(notarize2.clone()), false);
2956        assert_eq!(verifier.notarizes.len(), 2);
2957
2958        verifier.add(Voter::Notarize(notarize_diff.clone()), false);
2959        assert_eq!(verifier.notarizes.len(), 2);
2960
2961        let mut verifier2 = BatchVerifier::<S, Sha256>::new(schemes[0].clone(), Some(quorum));
2962        let round2 = Round::new(0, 2);
2963        let notarize_non_leader = create_notarize(&schemes[1], round2, 1, 3);
2964        let notarize_leader = create_notarize(&schemes[0], round2, 1, 3);
2965
2966        verifier2.set_leader(notarize_leader.signer());
2967        verifier2.add(Voter::Notarize(notarize_non_leader.clone()), false);
2968        assert!(verifier2.leader_proposal.is_none());
2969        assert_eq!(verifier2.notarizes.len(), 1);
2970
2971        verifier2.add(Voter::Notarize(notarize_leader.clone()), false);
2972        assert!(verifier2.leader_proposal.is_some());
2973        assert_eq!(
2974            verifier2.leader_proposal.as_ref().unwrap(),
2975            &notarize_leader.proposal
2976        );
2977        assert_eq!(verifier2.notarizes.len(), 2);
2978    }
2979
2980    #[test]
2981    fn test_batch_verifier_add_notarize() {
2982        batch_verifier_add_notarize(generate_bls12381_threshold_schemes(5, 123));
2983        batch_verifier_add_notarize(generate_ed25519_schemes(5, 123));
2984    }
2985
2986    fn batch_verifier_set_leader<S: Scheme + Clone>(schemes: Vec<S>) {
2987        let quorum = quorum(schemes.len() as u32);
2988        let mut verifier = BatchVerifier::<S, Sha256>::new(schemes[0].clone(), Some(quorum));
2989
2990        let round = Round::new(0, 1);
2991        let leader_notarize = create_notarize(&schemes[0], round, 0, 1);
2992        let other_notarize = create_notarize(&schemes[1], round, 0, 1);
2993
2994        verifier.add(Voter::Notarize(other_notarize.clone()), false);
2995        assert_eq!(verifier.notarizes.len(), 1);
2996
2997        let leader = leader_notarize.signer();
2998        verifier.set_leader(leader);
2999        assert_eq!(verifier.leader, Some(leader));
3000        assert!(verifier.leader_proposal.is_none());
3001        assert!(!verifier.notarizes_force);
3002        assert_eq!(verifier.notarizes.len(), 1);
3003
3004        verifier.add(Voter::Notarize(leader_notarize.clone()), false);
3005        assert!(verifier.leader_proposal.is_some());
3006        assert_eq!(
3007            verifier.leader_proposal.as_ref().unwrap(),
3008            &leader_notarize.proposal
3009        );
3010        assert!(verifier.notarizes_force);
3011        assert_eq!(verifier.notarizes.len(), 2);
3012    }
3013
3014    #[test]
3015    fn test_batch_verifier_set_leader() {
3016        batch_verifier_set_leader(generate_bls12381_threshold_schemes(5, 124));
3017        batch_verifier_set_leader(generate_ed25519_schemes(5, 124));
3018    }
3019
3020    fn batch_verifier_ready_and_verify_notarizes<S: Scheme + Clone>(schemes: Vec<S>) {
3021        let quorum = quorum(schemes.len() as u32);
3022        let mut verifier = BatchVerifier::<S, Sha256>::new(schemes[0].clone(), Some(quorum));
3023        let mut rng = OsRng;
3024        let round = Round::new(0, 1);
3025        let notarizes: Vec<_> = schemes
3026            .iter()
3027            .map(|scheme| create_notarize(scheme, round, 0, 1))
3028            .collect();
3029
3030        assert!(!verifier.ready_notarizes());
3031
3032        verifier.set_leader(notarizes[0].signer());
3033        verifier.add(Voter::Notarize(notarizes[0].clone()), false);
3034        assert!(verifier.ready_notarizes());
3035        assert_eq!(verifier.notarizes.len(), 1);
3036
3037        let (verified_once, failed_once) = verifier.verify_notarizes(&mut rng, NAMESPACE);
3038        assert_eq!(verified_once.len(), 1);
3039        assert!(failed_once.is_empty());
3040        assert_eq!(verifier.notarizes_verified, 1);
3041        assert!(verifier.notarizes.is_empty());
3042        assert!(!verifier.notarizes_force);
3043
3044        verifier.add(Voter::Notarize(notarizes[1].clone()), false);
3045        assert!(!verifier.ready_notarizes());
3046        verifier.add(Voter::Notarize(notarizes[2].clone()), false);
3047        assert!(!verifier.ready_notarizes());
3048        verifier.add(Voter::Notarize(notarizes[3].clone()), false);
3049        assert!(verifier.ready_notarizes());
3050        assert_eq!(verifier.notarizes.len(), 3);
3051
3052        let (verified_bulk, failed_bulk) = verifier.verify_notarizes(&mut rng, NAMESPACE);
3053        assert_eq!(verified_bulk.len(), 3);
3054        assert!(failed_bulk.is_empty());
3055        assert_eq!(verifier.notarizes_verified, 4);
3056        assert!(verifier.notarizes.is_empty());
3057        assert!(!verifier.ready_notarizes());
3058
3059        let mut verifier2 = BatchVerifier::<S, Sha256>::new(schemes[0].clone(), Some(quorum));
3060        let round2 = Round::new(0, 2);
3061        let leader_vote = create_notarize(&schemes[0], round2, 1, 10);
3062        let mut faulty_vote = create_notarize(&schemes[1], round2, 1, 10);
3063        verifier2.set_leader(leader_vote.signer());
3064        verifier2.add(Voter::Notarize(leader_vote.clone()), false);
3065        faulty_vote.vote.signer = (schemes.len() as u32) + 10;
3066        verifier2.add(Voter::Notarize(faulty_vote.clone()), false);
3067        assert!(verifier2.ready_notarizes());
3068
3069        let (verified_second, failed_second) = verifier2.verify_notarizes(&mut rng, NAMESPACE);
3070        assert_eq!(verified_second.len(), 1);
3071        assert!(verified_second
3072            .into_iter()
3073            .any(|v| matches!(v, Voter::Notarize(ref n) if n == &leader_vote)));
3074        assert_eq!(failed_second, vec![faulty_vote.signer()]);
3075    }
3076
3077    #[test]
3078    fn test_batch_verifier_ready_and_verify_notarizes() {
3079        batch_verifier_ready_and_verify_notarizes(generate_bls12381_threshold_schemes(5, 125));
3080        batch_verifier_ready_and_verify_notarizes(generate_ed25519_schemes(5, 125));
3081    }
3082
3083    fn batch_verifier_add_nullify<S: Scheme + Clone>(schemes: Vec<S>) {
3084        let quorum = quorum(schemes.len() as u32);
3085        let mut verifier = BatchVerifier::<S, Sha256>::new(schemes[0].clone(), Some(quorum));
3086        let round = Round::new(0, 1);
3087        let nullify = create_nullify(&schemes[0], round);
3088
3089        verifier.add(Voter::Nullify(nullify.clone()), false);
3090        assert_eq!(verifier.nullifies.len(), 1);
3091        assert_eq!(verifier.nullifies_verified, 0);
3092
3093        verifier.add(Voter::Nullify(nullify.clone()), true);
3094        assert_eq!(verifier.nullifies.len(), 1);
3095        assert_eq!(verifier.nullifies_verified, 1);
3096    }
3097
3098    #[test]
3099    fn test_batch_verifier_add_nullify() {
3100        batch_verifier_add_nullify(generate_bls12381_threshold_schemes(5, 127));
3101        batch_verifier_add_nullify(generate_ed25519_schemes(5, 127));
3102    }
3103
3104    fn batch_verifier_ready_and_verify_nullifies<S: Scheme + Clone>(schemes: Vec<S>) {
3105        let quorum = quorum(schemes.len() as u32);
3106        let mut verifier = BatchVerifier::<S, Sha256>::new(schemes[0].clone(), Some(quorum));
3107        let mut rng = OsRng;
3108        let round = Round::new(0, 1);
3109        let nullifies: Vec<_> = schemes
3110            .iter()
3111            .map(|scheme| create_nullify(scheme, round))
3112            .collect();
3113
3114        verifier.add(Voter::Nullify(nullifies[0].clone()), true);
3115        assert_eq!(verifier.nullifies_verified, 1);
3116
3117        verifier.add(Voter::Nullify(nullifies[1].clone()), false);
3118        assert!(!verifier.ready_nullifies());
3119        verifier.add(Voter::Nullify(nullifies[2].clone()), false);
3120        assert!(!verifier.ready_nullifies());
3121        verifier.add(Voter::Nullify(nullifies[3].clone()), false);
3122        assert!(verifier.ready_nullifies());
3123        assert_eq!(verifier.nullifies.len(), 3);
3124
3125        let (verified, failed) = verifier.verify_nullifies(&mut rng, NAMESPACE);
3126        assert_eq!(verified.len(), 3);
3127        assert!(failed.is_empty());
3128        assert_eq!(verifier.nullifies_verified, 4);
3129        assert!(verifier.nullifies.is_empty());
3130        assert!(!verifier.ready_nullifies());
3131    }
3132
3133    #[test]
3134    fn test_batch_verifier_ready_and_verify_nullifies() {
3135        batch_verifier_ready_and_verify_nullifies(generate_bls12381_threshold_schemes(5, 128));
3136        batch_verifier_ready_and_verify_nullifies(generate_ed25519_schemes(5, 128));
3137    }
3138
3139    fn batch_verifier_add_finalize<S: Scheme + Clone>(schemes: Vec<S>) {
3140        let quorum = quorum(schemes.len() as u32);
3141        let mut verifier = BatchVerifier::<S, Sha256>::new(schemes[0].clone(), Some(quorum));
3142        let round = Round::new(0, 1);
3143        let finalize_a = create_finalize(&schemes[0], round, 0, 1);
3144        let finalize_b = create_finalize(&schemes[1], round, 0, 2);
3145
3146        verifier.add(Voter::Finalize(finalize_b.clone()), false);
3147        assert_eq!(verifier.finalizes.len(), 1);
3148        assert_eq!(verifier.finalizes_verified, 0);
3149
3150        verifier.add(Voter::Finalize(finalize_a.clone()), false);
3151        assert_eq!(verifier.finalizes.len(), 2);
3152
3153        verifier.set_leader(finalize_a.signer());
3154        assert!(verifier.leader_proposal.is_none());
3155        verifier.set_leader_proposal(finalize_a.proposal.clone());
3156        assert_eq!(verifier.finalizes.len(), 1);
3157        assert_eq!(verifier.finalizes[0], finalize_a);
3158        assert_eq!(verifier.finalizes_verified, 0);
3159
3160        verifier.add(Voter::Finalize(finalize_a.clone()), true);
3161        assert_eq!(verifier.finalizes.len(), 1);
3162        assert_eq!(verifier.finalizes_verified, 1);
3163
3164        verifier.add(Voter::Finalize(finalize_b.clone()), false);
3165        assert_eq!(verifier.finalizes.len(), 1);
3166        assert_eq!(verifier.finalizes_verified, 1);
3167    }
3168
3169    #[test]
3170    fn test_batch_verifier_add_finalize() {
3171        batch_verifier_add_finalize(generate_bls12381_threshold_schemes(5, 129));
3172        batch_verifier_add_finalize(generate_ed25519_schemes(5, 129));
3173    }
3174
3175    fn batch_verifier_ready_and_verify_finalizes<S: Scheme + Clone>(schemes: Vec<S>) {
3176        let quorum = quorum(schemes.len() as u32);
3177        let mut verifier = BatchVerifier::<S, Sha256>::new(schemes[0].clone(), Some(quorum));
3178        let mut rng = OsRng;
3179        let round = Round::new(0, 1);
3180        let finalizes: Vec<_> = schemes
3181            .iter()
3182            .map(|scheme| create_finalize(scheme, round, 0, 1))
3183            .collect();
3184
3185        assert!(!verifier.ready_finalizes());
3186
3187        verifier.set_leader(finalizes[0].signer());
3188        verifier.set_leader_proposal(finalizes[0].proposal.clone());
3189
3190        verifier.add(Voter::Finalize(finalizes[0].clone()), true);
3191        assert_eq!(verifier.finalizes_verified, 1);
3192        assert!(verifier.finalizes.is_empty());
3193
3194        verifier.add(Voter::Finalize(finalizes[1].clone()), false);
3195        assert!(!verifier.ready_finalizes());
3196        verifier.add(Voter::Finalize(finalizes[2].clone()), false);
3197        assert!(!verifier.ready_finalizes());
3198        verifier.add(Voter::Finalize(finalizes[3].clone()), false);
3199        assert!(verifier.ready_finalizes());
3200
3201        let (verified, failed) = verifier.verify_finalizes(&mut rng, NAMESPACE);
3202        assert_eq!(verified.len(), 3);
3203        assert!(failed.is_empty());
3204        assert_eq!(verifier.finalizes_verified, 4);
3205        assert!(verifier.finalizes.is_empty());
3206        assert!(!verifier.ready_finalizes());
3207    }
3208
3209    #[test]
3210    fn test_batch_verifier_ready_and_verify_finalizes() {
3211        batch_verifier_ready_and_verify_finalizes(generate_bls12381_threshold_schemes(5, 130));
3212        batch_verifier_ready_and_verify_finalizes(generate_ed25519_schemes(5, 130));
3213    }
3214
3215    fn batch_verifier_quorum_none<S: Scheme + Clone>(schemes: Vec<S>) {
3216        let mut rng = OsRng;
3217        let round = Round::new(0, 1);
3218
3219        let mut verifier_notarize = BatchVerifier::<S, Sha256>::new(schemes[0].clone(), None);
3220        let notarize = create_notarize(&schemes[0], round, 0, 1);
3221        assert!(!verifier_notarize.ready_notarizes());
3222        verifier_notarize.set_leader(notarize.signer());
3223        verifier_notarize.add(Voter::Notarize(notarize.clone()), false);
3224        assert!(verifier_notarize.ready_notarizes());
3225        let (verified_notarize, failed_notarize) =
3226            verifier_notarize.verify_notarizes(&mut rng, NAMESPACE);
3227        assert_eq!(verified_notarize.len(), 1);
3228        assert!(failed_notarize.is_empty());
3229        assert_eq!(verifier_notarize.notarizes_verified, 1);
3230        assert!(!verifier_notarize.ready_notarizes());
3231
3232        let mut verifier_null = BatchVerifier::<S, Sha256>::new(schemes[0].clone(), None);
3233        let nullify = create_nullify(&schemes[0], round);
3234        assert!(!verifier_null.ready_nullifies());
3235        verifier_null.add(Voter::Nullify(nullify.clone()), false);
3236        assert!(verifier_null.ready_nullifies());
3237        let (verified_null, failed_null) = verifier_null.verify_nullifies(&mut rng, NAMESPACE);
3238        assert_eq!(verified_null.len(), 1);
3239        assert!(failed_null.is_empty());
3240        assert_eq!(verifier_null.nullifies_verified, 1);
3241        assert!(!verifier_null.ready_nullifies());
3242
3243        let mut verifier_final = BatchVerifier::<S, Sha256>::new(schemes[0].clone(), None);
3244        let finalize = create_finalize(&schemes[0], round, 0, 1);
3245        assert!(!verifier_final.ready_finalizes());
3246        verifier_final.set_leader(finalize.signer());
3247        verifier_final.set_leader_proposal(finalize.proposal.clone());
3248        verifier_final.add(Voter::Finalize(finalize.clone()), false);
3249        assert!(verifier_final.ready_finalizes());
3250        let (verified_fin, failed_fin) = verifier_final.verify_finalizes(&mut rng, NAMESPACE);
3251        assert_eq!(verified_fin.len(), 1);
3252        assert!(failed_fin.is_empty());
3253        assert_eq!(verifier_final.finalizes_verified, 1);
3254        assert!(!verifier_final.ready_finalizes());
3255    }
3256
3257    #[test]
3258    fn test_batch_verifier_quorum_none() {
3259        batch_verifier_quorum_none(generate_bls12381_threshold_schemes(3, 200));
3260        batch_verifier_quorum_none(generate_ed25519_schemes(3, 200));
3261    }
3262
3263    fn batch_verifier_leader_proposal_filters_messages<S: Scheme + Clone>(schemes: Vec<S>) {
3264        let quorum = quorum(schemes.len() as u32);
3265        let mut verifier = BatchVerifier::<S, Sha256>::new(schemes[0].clone(), Some(quorum));
3266        let round = Round::new(0, 1);
3267        let proposal_a = Proposal::new(round, 0, sample_digest(10));
3268        let proposal_b = Proposal::new(round, 0, sample_digest(20));
3269
3270        let notarize_a = Notarize::sign(&schemes[0], NAMESPACE, proposal_a.clone()).unwrap();
3271        let notarize_b = Notarize::sign(&schemes[1], NAMESPACE, proposal_b.clone()).unwrap();
3272        let finalize_a = Finalize::sign(&schemes[0], NAMESPACE, proposal_a.clone()).unwrap();
3273        let finalize_b = Finalize::sign(&schemes[1], NAMESPACE, proposal_b.clone()).unwrap();
3274
3275        verifier.add(Voter::Notarize(notarize_a.clone()), false);
3276        verifier.add(Voter::Notarize(notarize_b.clone()), false);
3277        verifier.add(Voter::Finalize(finalize_a.clone()), false);
3278        verifier.add(Voter::Finalize(finalize_b.clone()), false);
3279
3280        assert_eq!(verifier.notarizes.len(), 2);
3281        assert_eq!(verifier.finalizes.len(), 2);
3282
3283        verifier.set_leader(notarize_a.signer());
3284
3285        assert!(verifier.notarizes_force);
3286        assert_eq!(verifier.notarizes.len(), 1);
3287        assert_eq!(verifier.notarizes[0].proposal, proposal_a);
3288        assert_eq!(verifier.finalizes.len(), 1);
3289        assert_eq!(verifier.finalizes[0].proposal, proposal_a);
3290    }
3291
3292    #[test]
3293    fn test_batch_verifier_leader_proposal_filters_messages() {
3294        batch_verifier_leader_proposal_filters_messages(generate_bls12381_threshold_schemes(
3295            3, 201,
3296        ));
3297        batch_verifier_leader_proposal_filters_messages(generate_ed25519_schemes(3, 201));
3298    }
3299
3300    fn batch_verifier_set_leader_twice_panics<S: Scheme + Clone>(schemes: Vec<S>) {
3301        let mut verifier = BatchVerifier::<S, Sha256>::new(schemes[0].clone(), Some(3));
3302        verifier.set_leader(0);
3303        verifier.set_leader(1);
3304    }
3305
3306    #[test]
3307    #[should_panic(expected = "self.leader.is_none()")]
3308    fn test_batch_verifier_set_leader_twice_panics_bls() {
3309        batch_verifier_set_leader_twice_panics(generate_bls12381_threshold_schemes(3, 212));
3310    }
3311
3312    #[test]
3313    #[should_panic(expected = "self.leader.is_none()")]
3314    fn test_batch_verifier_set_leader_twice_panics_ed() {
3315        batch_verifier_set_leader_twice_panics(generate_ed25519_schemes(3, 213));
3316    }
3317
3318    fn batch_verifier_add_recovered_message_panics<S: Scheme + Clone>(schemes: Vec<S>) {
3319        let quorum = quorum(schemes.len() as u32);
3320        let mut verifier = BatchVerifier::<S, Sha256>::new(schemes[0].clone(), Some(quorum));
3321        let notarization = create_notarization(&schemes, Round::new(0, 1), 0, 1, quorum);
3322        verifier.add(Voter::Notarization(notarization), false);
3323    }
3324
3325    #[test]
3326    #[should_panic(expected = "should not be adding recovered messages to partial verifier")]
3327    fn test_batch_verifier_add_recovered_message_panics_bls() {
3328        batch_verifier_add_recovered_message_panics(generate_bls12381_threshold_schemes(3, 213));
3329    }
3330
3331    #[test]
3332    #[should_panic(expected = "should not be adding recovered messages to partial verifier")]
3333    fn test_batch_verifier_add_recovered_message_panics_ed() {
3334        batch_verifier_add_recovered_message_panics(generate_ed25519_schemes(3, 214));
3335    }
3336
3337    fn batch_verifier_notarizes_force_flag<S: Scheme + Clone>(schemes: Vec<S>) {
3338        let quorum = quorum(schemes.len() as u32);
3339        let mut verifier = BatchVerifier::<S, Sha256>::new(schemes[0].clone(), Some(quorum));
3340        let mut rng = OsRng;
3341        let round = Round::new(0, 1);
3342        let leader_vote = create_notarize(&schemes[0], round, 0, 1);
3343
3344        verifier.set_leader(leader_vote.signer());
3345        verifier.add(Voter::Notarize(leader_vote.clone()), false);
3346
3347        assert!(
3348            verifier.notarizes_force,
3349            "notarizes_force should be true after leader's proposal is set"
3350        );
3351        assert!(verifier.ready_notarizes());
3352
3353        let (verified, _) = verifier.verify_notarizes(&mut rng, NAMESPACE);
3354        assert_eq!(verified.len(), 1);
3355        assert!(
3356            !verifier.notarizes_force,
3357            "notarizes_force should be false after verification"
3358        );
3359        assert!(!verifier.ready_notarizes());
3360    }
3361
3362    #[test]
3363    fn test_ready_notarizes_behavior_with_force_flag() {
3364        batch_verifier_notarizes_force_flag(generate_bls12381_threshold_schemes(3, 203));
3365        batch_verifier_notarizes_force_flag(generate_ed25519_schemes(3, 203));
3366    }
3367
3368    fn batch_verifier_ready_notarizes_without_leader<S: Scheme + Clone>(schemes: Vec<S>) {
3369        let quorum = quorum(schemes.len() as u32);
3370        let mut verifier = BatchVerifier::<S, Sha256>::new(schemes[0].clone(), Some(quorum));
3371        let round = Round::new(0, 1);
3372
3373        let notarizes: Vec<_> = schemes
3374            .iter()
3375            .take(quorum as usize)
3376            .map(|scheme| create_notarize(scheme, round, 0, 1))
3377            .collect();
3378
3379        for vote in notarizes.iter() {
3380            verifier.add(Voter::Notarize(vote.clone()), false);
3381        }
3382
3383        assert!(
3384            !verifier.ready_notarizes(),
3385            "Should not be ready without leader/proposal set"
3386        );
3387
3388        verifier.set_leader(notarizes[0].signer());
3389        assert!(
3390            verifier.ready_notarizes(),
3391            "Should be ready once leader is set"
3392        );
3393    }
3394
3395    #[test]
3396    fn test_ready_notarizes_without_leader_or_proposal() {
3397        batch_verifier_ready_notarizes_without_leader(generate_bls12381_threshold_schemes(3, 204));
3398        batch_verifier_ready_notarizes_without_leader(generate_ed25519_schemes(3, 204));
3399    }
3400
3401    fn batch_verifier_ready_finalizes_without_leader<S: Scheme + Clone>(schemes: Vec<S>) {
3402        let quorum = quorum(schemes.len() as u32);
3403        let mut verifier = BatchVerifier::<S, Sha256>::new(schemes[0].clone(), Some(quorum));
3404        let round = Round::new(0, 1);
3405        let finalizes: Vec<_> = schemes
3406            .iter()
3407            .take(quorum as usize)
3408            .map(|scheme| create_finalize(scheme, round, 0, 1))
3409            .collect();
3410
3411        for finalize in finalizes.iter() {
3412            verifier.add(Voter::Finalize(finalize.clone()), false);
3413        }
3414
3415        assert!(
3416            !verifier.ready_finalizes(),
3417            "Should not be ready without leader/proposal set"
3418        );
3419
3420        verifier.set_leader(finalizes[0].signer());
3421        assert!(
3422            !verifier.ready_finalizes(),
3423            "Should not be ready without leader_proposal set"
3424        );
3425    }
3426
3427    #[test]
3428    fn test_ready_finalizes_without_leader_or_proposal() {
3429        batch_verifier_ready_finalizes_without_leader(generate_bls12381_threshold_schemes(3, 205));
3430        batch_verifier_ready_finalizes_without_leader(generate_ed25519_schemes(3, 205));
3431    }
3432
3433    fn batch_verifier_verify_notarizes_empty<S: Scheme + Clone>(schemes: Vec<S>) {
3434        let quorum = quorum(schemes.len() as u32);
3435        let mut verifier = BatchVerifier::<S, Sha256>::new(schemes[0].clone(), Some(quorum));
3436        let round = Round::new(0, 1);
3437        let leader_proposal = Proposal::new(round, 0, sample_digest(1));
3438        verifier.set_leader_proposal(leader_proposal);
3439        assert!(verifier.notarizes_force);
3440        assert!(verifier.notarizes.is_empty());
3441        assert!(!verifier.ready_notarizes());
3442    }
3443
3444    #[test]
3445    fn test_verify_notarizes_empty_pending_when_forced() {
3446        batch_verifier_verify_notarizes_empty(generate_bls12381_threshold_schemes(3, 206));
3447        batch_verifier_verify_notarizes_empty(generate_ed25519_schemes(3, 206));
3448    }
3449
3450    fn batch_verifier_verify_nullifies_empty<S: Scheme + Clone>(schemes: Vec<S>) {
3451        let quorum = quorum(schemes.len() as u32);
3452        let mut verifier = BatchVerifier::<S, Sha256>::new(schemes[0].clone(), Some(quorum));
3453        let mut rng = OsRng;
3454        assert!(verifier.nullifies.is_empty());
3455        assert!(!verifier.ready_nullifies());
3456        let (verified, failed) = verifier.verify_nullifies(&mut rng, NAMESPACE);
3457        assert!(verified.is_empty());
3458        assert!(failed.is_empty());
3459        assert_eq!(verifier.nullifies_verified, 0);
3460    }
3461
3462    #[test]
3463    fn test_verify_nullifies_empty_pending() {
3464        batch_verifier_verify_nullifies_empty(generate_bls12381_threshold_schemes(3, 207));
3465        batch_verifier_verify_nullifies_empty(generate_ed25519_schemes(3, 207));
3466    }
3467
3468    fn batch_verifier_verify_finalizes_empty<S: Scheme + Clone>(schemes: Vec<S>) {
3469        let quorum = quorum(schemes.len() as u32);
3470        let mut verifier = BatchVerifier::<S, Sha256>::new(schemes[0].clone(), Some(quorum));
3471        let mut rng = OsRng;
3472        verifier.set_leader(0);
3473        assert!(verifier.finalizes.is_empty());
3474        assert!(!verifier.ready_finalizes());
3475        let (verified, failed) = verifier.verify_finalizes(&mut rng, NAMESPACE);
3476        assert!(verified.is_empty());
3477        assert!(failed.is_empty());
3478        assert_eq!(verifier.finalizes_verified, 0);
3479    }
3480
3481    #[test]
3482    fn test_verify_finalizes_empty_pending() {
3483        batch_verifier_verify_finalizes_empty(generate_bls12381_threshold_schemes(3, 208));
3484        batch_verifier_verify_finalizes_empty(generate_ed25519_schemes(3, 208));
3485    }
3486
3487    fn batch_verifier_ready_notarizes_exact_quorum<S: Scheme + Clone>(schemes: Vec<S>) {
3488        let quorum = quorum(schemes.len() as u32);
3489        let mut verifier = BatchVerifier::<S, Sha256>::new(schemes[0].clone(), Some(quorum));
3490        let mut rng = OsRng;
3491        let round = Round::new(0, 1);
3492
3493        let leader_vote = create_notarize(&schemes[0], round, 0, 1);
3494        verifier.set_leader(leader_vote.signer());
3495        verifier.add(Voter::Notarize(leader_vote.clone()), true);
3496        assert_eq!(verifier.notarizes_verified, 1);
3497
3498        let second_vote = create_notarize(&schemes[1], round, 0, 1);
3499        verifier.add(Voter::Notarize(second_vote.clone()), false);
3500        assert!(verifier.ready_notarizes());
3501        let (verified_once, failed_once) = verifier.verify_notarizes(&mut rng, NAMESPACE);
3502        assert_eq!(verified_once.len(), 1);
3503        assert!(failed_once.is_empty());
3504        assert_eq!(verifier.notarizes_verified, 2);
3505
3506        for scheme in schemes.iter().take(quorum as usize).skip(2) {
3507            assert!(!verifier.ready_notarizes());
3508            verifier.add(Voter::Notarize(create_notarize(scheme, round, 0, 1)), false);
3509        }
3510
3511        assert!(verifier.ready_notarizes());
3512    }
3513
3514    #[test]
3515    fn test_ready_notarizes_exact_quorum() {
3516        batch_verifier_ready_notarizes_exact_quorum(generate_bls12381_threshold_schemes(5, 209));
3517        batch_verifier_ready_notarizes_exact_quorum(generate_ed25519_schemes(5, 209));
3518    }
3519
3520    fn batch_verifier_ready_nullifies_exact_quorum<S: Scheme + Clone>(schemes: Vec<S>) {
3521        let quorum = quorum(schemes.len() as u32);
3522        let mut verifier = BatchVerifier::<S, Sha256>::new(schemes[0].clone(), Some(quorum));
3523        let round = Round::new(0, 1);
3524
3525        verifier.add(Voter::Nullify(create_nullify(&schemes[0], round)), true);
3526        assert_eq!(verifier.nullifies_verified, 1);
3527
3528        for scheme in schemes.iter().take(quorum as usize).skip(1) {
3529            assert!(!verifier.ready_nullifies());
3530            verifier.add(Voter::Nullify(create_nullify(scheme, round)), false);
3531        }
3532
3533        assert!(verifier.ready_nullifies());
3534    }
3535
3536    #[test]
3537    fn test_ready_nullifies_exact_quorum() {
3538        batch_verifier_ready_nullifies_exact_quorum(generate_bls12381_threshold_schemes(5, 210));
3539        batch_verifier_ready_nullifies_exact_quorum(generate_ed25519_schemes(5, 210));
3540    }
3541
3542    fn batch_verifier_ready_finalizes_exact_quorum<S: Scheme + Clone>(schemes: Vec<S>) {
3543        let quorum = quorum(schemes.len() as u32);
3544        let mut verifier = BatchVerifier::<S, Sha256>::new(schemes[0].clone(), Some(quorum));
3545        let round = Round::new(0, 1);
3546        let leader_finalize = create_finalize(&schemes[0], round, 0, 1);
3547        verifier.set_leader(leader_finalize.signer());
3548        verifier.set_leader_proposal(leader_finalize.proposal.clone());
3549        verifier.add(Voter::Finalize(leader_finalize), true);
3550        assert_eq!(verifier.finalizes_verified, 1);
3551
3552        for scheme in schemes.iter().take(quorum as usize).skip(1) {
3553            assert!(!verifier.ready_finalizes());
3554            verifier.add(Voter::Finalize(create_finalize(scheme, round, 0, 1)), false);
3555        }
3556
3557        assert!(verifier.ready_finalizes());
3558    }
3559
3560    #[test]
3561    fn test_ready_finalizes_exact_quorum() {
3562        batch_verifier_ready_finalizes_exact_quorum(generate_bls12381_threshold_schemes(5, 211));
3563        batch_verifier_ready_finalizes_exact_quorum(generate_ed25519_schemes(5, 211));
3564    }
3565
3566    fn batch_verifier_ready_notarizes_quorum_already_met_by_verified<S: Scheme + Clone>(
3567        schemes: Vec<S>,
3568    ) {
3569        let quorum = quorum(schemes.len() as u32);
3570        assert!(
3571            schemes.len() > quorum as usize,
3572            "test requires more validators than the quorum"
3573        );
3574        let mut verifier = BatchVerifier::<S, Sha256>::new(schemes[0].clone(), Some(quorum));
3575        let round = Round::new(0, 1);
3576
3577        // Pre-load the leader vote as if it had already been processed.
3578        let leader_vote = create_notarize(&schemes[0], round, 0, 1);
3579        verifier.set_leader(leader_vote.signer());
3580        verifier.add(Voter::Notarize(leader_vote.clone()), false);
3581        verifier.notarizes_force = false;
3582
3583        // Mark enough verified notarizes to satisfy the quorum outright.
3584        for scheme in schemes.iter().take(quorum as usize) {
3585            verifier.add(Voter::Notarize(create_notarize(scheme, round, 0, 1)), true);
3586        }
3587        assert_eq!(verifier.notarizes_verified, quorum as usize);
3588        assert!(
3589            !verifier.ready_notarizes(),
3590            "Should not be ready if quorum already met by verified messages"
3591        );
3592
3593        // Additional pending votes must not flip readiness in this situation.
3594        let extra_vote = create_notarize(&schemes[quorum as usize], round, 0, 1);
3595        verifier.add(Voter::Notarize(extra_vote), false);
3596        assert!(
3597            !verifier.ready_notarizes(),
3598            "Should not be ready if quorum already met by verified messages"
3599        );
3600    }
3601
3602    #[test]
3603    fn test_ready_notarizes_quorum_already_met_by_verified() {
3604        batch_verifier_ready_notarizes_quorum_already_met_by_verified(
3605            generate_bls12381_threshold_schemes(5, 212),
3606        );
3607        batch_verifier_ready_notarizes_quorum_already_met_by_verified(generate_ed25519_schemes(
3608            5, 212,
3609        ));
3610    }
3611
3612    fn batch_verifier_ready_nullifies_quorum_already_met_by_verified<S: Scheme + Clone>(
3613        schemes: Vec<S>,
3614    ) {
3615        let quorum = quorum(schemes.len() as u32);
3616        assert!(
3617            schemes.len() > quorum as usize,
3618            "test requires more validators than the quorum"
3619        );
3620        let mut verifier = BatchVerifier::<S, Sha256>::new(schemes[0].clone(), Some(quorum));
3621        let round = Round::new(0, 1);
3622
3623        // First mark a quorum's worth of verified nullifies.
3624        for scheme in schemes.iter().take(quorum as usize) {
3625            verifier.add(Voter::Nullify(create_nullify(scheme, round)), true);
3626        }
3627        assert_eq!(verifier.nullifies_verified, quorum as usize);
3628        assert!(
3629            !verifier.ready_nullifies(),
3630            "Should not be ready if quorum already met by verified messages"
3631        );
3632
3633        // Pending messages alone cannot transition the batch to ready.
3634        let extra_nullify = create_nullify(&schemes[quorum as usize], round);
3635        verifier.add(Voter::Nullify(extra_nullify), false);
3636        assert!(
3637            !verifier.ready_nullifies(),
3638            "Should not be ready if quorum already met by verified messages"
3639        );
3640    }
3641
3642    #[test]
3643    fn test_ready_nullifies_quorum_already_met_by_verified() {
3644        batch_verifier_ready_nullifies_quorum_already_met_by_verified(
3645            generate_bls12381_threshold_schemes(5, 213),
3646        );
3647        batch_verifier_ready_nullifies_quorum_already_met_by_verified(generate_ed25519_schemes(
3648            5, 213,
3649        ));
3650    }
3651
3652    fn batch_verifier_ready_finalizes_quorum_already_met_by_verified<S: Scheme + Clone>(
3653        schemes: Vec<S>,
3654    ) {
3655        let quorum = quorum(schemes.len() as u32);
3656        assert!(
3657            schemes.len() > quorum as usize,
3658            "test requires more validators than the quorum"
3659        );
3660        let mut verifier = BatchVerifier::<S, Sha256>::new(schemes[0].clone(), Some(quorum));
3661        let round = Round::new(0, 1);
3662
3663        // Prime the leader state so the quorum is already satisfied by verified finalizes.
3664        let leader_finalize = create_finalize(&schemes[0], round, 0, 1);
3665        verifier.set_leader(leader_finalize.signer());
3666        verifier.set_leader_proposal(leader_finalize.proposal.clone());
3667
3668        // Feed exactly the number of verified finalizes required to hit the quorum.
3669        for scheme in schemes.iter().take(quorum as usize) {
3670            verifier.add(Voter::Finalize(create_finalize(scheme, round, 0, 1)), true);
3671        }
3672        assert_eq!(verifier.finalizes_verified, quorum as usize);
3673        assert!(
3674            !verifier.ready_finalizes(),
3675            "Should not be ready if quorum already met by verified messages"
3676        );
3677
3678        // Ensure additional pending finalizes do not incorrectly trigger readiness.
3679        let extra_finalize = create_finalize(&schemes[quorum as usize], round, 0, 1);
3680        verifier.add(Voter::Finalize(extra_finalize), false);
3681        assert!(
3682            !verifier.ready_finalizes(),
3683            "Should not be ready if quorum already met by verified messages"
3684        );
3685    }
3686
3687    #[test]
3688    fn test_ready_finalizes_quorum_already_met_by_verified() {
3689        batch_verifier_ready_finalizes_quorum_already_met_by_verified(
3690            generate_bls12381_threshold_schemes(5, 214),
3691        );
3692        batch_verifier_ready_finalizes_quorum_already_met_by_verified(generate_ed25519_schemes(
3693            5, 214,
3694        ));
3695    }
3696
3697    struct MockAttributable(u32);
3698
3699    impl Attributable for MockAttributable {
3700        fn signer(&self) -> u32 {
3701            self.0
3702        }
3703    }
3704
3705    #[test]
3706    fn test_attributable_vec() {
3707        let mut vec = AttributableVec::new(5);
3708        assert_eq!(vec.len(), 0);
3709        assert!(vec.is_empty());
3710
3711        assert!(vec.push(MockAttributable(3)));
3712        assert_eq!(vec.len(), 1);
3713        assert!(!vec.is_empty());
3714        let mut iter = vec.iter();
3715        assert!(matches!(iter.next(), Some(a) if a.signer() == 3));
3716        assert!(iter.next().is_none());
3717        drop(iter);
3718
3719        assert!(vec.push(MockAttributable(1)));
3720        assert_eq!(vec.len(), 2);
3721        assert!(!vec.is_empty());
3722        let mut iter = vec.iter();
3723        assert!(matches!(iter.next(), Some(a) if a.signer() == 1));
3724        assert!(matches!(iter.next(), Some(a) if a.signer() == 3));
3725        assert!(iter.next().is_none());
3726        drop(iter);
3727
3728        assert!(!vec.push(MockAttributable(3)));
3729        assert_eq!(vec.len(), 2);
3730        assert!(!vec.is_empty());
3731        let mut iter = vec.iter();
3732        assert!(matches!(iter.next(), Some(a) if a.signer() == 1));
3733        assert!(matches!(iter.next(), Some(a) if a.signer() == 3));
3734        assert!(iter.next().is_none());
3735        drop(iter);
3736    }
3737}