1use std::{
10 borrow::Cow,
11 fmt::{self, Debug, Display, Formatter},
12 hash::Hash,
13 marker::PhantomData,
14};
15
16use alloy_primitives::{FixedBytes, U256};
17use committable::{Commitment, Committable};
18use hotshot_utils::anytrace::*;
19use serde::{
20 Deserialize, Deserializer, Serialize, Serializer,
21 de::{self, SeqAccess, Visitor},
22 ser::SerializeTuple,
23};
24
25use crate::{
26 PeerConfig,
27 data::{EpochNumber, Leaf2, ViewNumber, serialize_signature2},
28 epoch_membership::EpochMembership,
29 light_client::{LightClientState, StakeTableState},
30 message::UpgradeLock,
31 simple_vote::{
32 DaData, DaData2, HasEpoch, LockView, NextEpochQuorumData2, QuorumData, QuorumData2,
33 QuorumMarker, TimeoutData, TimeoutData2, TimeoutLock, UpgradeProposalData,
34 UpgradeProposalData2, VersionedVoteData, ViewSyncCommitData, ViewSyncCommitData2,
35 ViewSyncFinalizeData, ViewSyncFinalizeData2, ViewSyncPreCommitData, ViewSyncPreCommitData2,
36 Vote2Data, Voteable,
37 },
38 stake_table::{HSStakeTable, StakeTableEntries},
39 traits::{
40 node_implementation::NodeType,
41 signature_key::{SignatureKey, StateSignatureKey},
42 },
43 utils::{is_epoch_root, is_epoch_transition},
44 vote::{Certificate, HasViewNumber},
45};
46
47mod timeout3;
48
49pub use timeout3::{LatestTimeoutSignatures, TimeoutCertificate3, TimeoutSignatures};
50
51pub trait Threshold<TYPES: NodeType> {
53 fn threshold(membership: &EpochMembership<TYPES>) -> U256;
55}
56
57#[derive(Serialize, Deserialize, Eq, Hash, PartialEq, Debug, Clone)]
59pub struct SuccessThreshold {}
60
61impl<TYPES: NodeType> Threshold<TYPES> for SuccessThreshold {
62 fn threshold(membership: &EpochMembership<TYPES>) -> U256 {
63 membership.success_threshold()
64 }
65}
66
67#[derive(Serialize, Deserialize, Eq, Hash, PartialEq, Debug, Clone)]
69pub struct OneHonestThreshold {}
70
71impl<TYPES: NodeType> Threshold<TYPES> for OneHonestThreshold {
72 fn threshold(membership: &EpochMembership<TYPES>) -> U256 {
73 membership.failure_threshold()
74 }
75}
76
77#[derive(Serialize, Deserialize, Eq, Hash, PartialEq, Debug, Clone)]
79pub struct UpgradeThreshold {}
80
81impl<TYPES: NodeType> Threshold<TYPES> for UpgradeThreshold {
82 fn threshold(membership: &EpochMembership<TYPES>) -> U256 {
83 membership.upgrade_threshold()
84 }
85}
86
87#[derive(Serialize, Deserialize, Eq, Hash, PartialEq, Debug, Clone)]
89pub struct SimpleCertificate<
90 TYPES: NodeType,
91 VOTEABLE: Voteable<TYPES>,
92 THRESHOLD: Threshold<TYPES>,
93> {
94 pub data: VOTEABLE,
96 vote_commitment: Commitment<VOTEABLE>,
98 pub view_number: ViewNumber,
100 pub signatures: Option<<TYPES::SignatureKey as SignatureKey>::QcType>,
102 pub _pd: PhantomData<(TYPES, THRESHOLD)>,
104}
105
106impl<TYPES: NodeType, VOTEABLE: Voteable<TYPES>, THRESHOLD: Threshold<TYPES>>
107 SimpleCertificate<TYPES, VOTEABLE, THRESHOLD>
108{
109 pub fn vote_commitment(&self) -> Commitment<VOTEABLE> {
112 self.vote_commitment
113 }
114
115 pub fn new(
117 data: VOTEABLE,
118 vote_commitment: Commitment<VOTEABLE>,
119 view_number: ViewNumber,
120 signatures: Option<<TYPES::SignatureKey as SignatureKey>::QcType>,
121 pd: PhantomData<(TYPES, THRESHOLD)>,
122 ) -> Self {
123 Self {
124 data,
125 vote_commitment,
126 view_number,
127 signatures,
128 _pd: pd,
129 }
130 }
131
132 fn signers(
133 &self,
134 stake_table: &[<TYPES::SignatureKey as SignatureKey>::StakeTableEntry],
135 threshold: U256,
136 ) -> Result<Vec<<TYPES::SignatureKey as SignatureKey>::VerificationKeyType>> {
137 if self.view_number == ViewNumber::genesis() {
138 return Ok(vec![]);
139 }
140 let real_qc_pp =
141 <TYPES::SignatureKey as SignatureKey>::public_parameter(stake_table, threshold);
142
143 let Some(ref signatures) = self.signatures else {
144 bail!("No signatures found while retrieving signers");
145 };
146
147 <TYPES::SignatureKey as SignatureKey>::signers(&real_qc_pp, signatures)
148 .wrap()
149 .context(|e| warn!("Tracing signers: {e}"))
150 }
151}
152
153impl<TYPES: NodeType, VOTEABLE: Voteable<TYPES> + Committable, THRESHOLD: Threshold<TYPES>>
154 Committable for SimpleCertificate<TYPES, VOTEABLE, THRESHOLD>
155{
156 fn commit(&self) -> Commitment<Self> {
157 let signature_bytes = match self.signatures.as_ref() {
158 Some(sigs) => serialize_signature2::<TYPES>(sigs),
159 None => vec![],
160 };
161 committable::RawCommitmentBuilder::new("Certificate")
162 .field("data", self.data.commit())
163 .field("vote_commitment", self.vote_commitment)
164 .field("view number", self.view_number.commit())
165 .var_size_field("signatures", &signature_bytes)
166 .finalize()
167 }
168}
169
170impl<TYPES: NodeType, THRESHOLD: Threshold<TYPES>> Certificate<TYPES, DaData>
171 for SimpleCertificate<TYPES, DaData, THRESHOLD>
172{
173 type Voteable = DaData;
174 type Threshold = THRESHOLD;
175
176 fn create_signed_certificate(
177 vote_commitment: Commitment<VersionedVoteData<TYPES, DaData>>,
178 data: Self::Voteable,
179 sig: <TYPES::SignatureKey as SignatureKey>::QcType,
180 view: ViewNumber,
181 ) -> Self {
182 let vote_commitment_bytes: [u8; 32] = vote_commitment.into();
183
184 SimpleCertificate {
185 data,
186 vote_commitment: Commitment::from_raw(vote_commitment_bytes),
187 view_number: view,
188 signatures: Some(sig),
189 _pd: PhantomData,
190 }
191 }
192 fn is_valid_cert(
193 &self,
194 stake_table: &[<TYPES::SignatureKey as SignatureKey>::StakeTableEntry],
195 threshold: U256,
196 upgrade_lock: &UpgradeLock<TYPES>,
197 ) -> Result<()> {
198 if self.view_number == ViewNumber::genesis() {
199 return Ok(());
200 }
201 let real_qc_pp =
202 <TYPES::SignatureKey as SignatureKey>::public_parameter(stake_table, threshold);
203 let commit = self.data_commitment(upgrade_lock)?;
204
205 let Some(ref signatures) = self.signatures else {
206 bail!("No signatures found while validating certificate");
207 };
208
209 <TYPES::SignatureKey as SignatureKey>::check(&real_qc_pp, commit.as_ref(), signatures)
210 .wrap()
211 .context(|e| warn!("Signature check failed: {e}"))
212 }
213 fn signers(
214 &self,
215 stake_table: &[<TYPES::SignatureKey as SignatureKey>::StakeTableEntry],
216 threshold: U256,
217 ) -> Result<Vec<<TYPES::SignatureKey as SignatureKey>::VerificationKeyType>> {
218 self.signers(stake_table, threshold)
219 }
220 fn stake_table_entry(
222 membership: &EpochMembership<TYPES>,
223 pub_key: &TYPES::SignatureKey,
224 ) -> Option<PeerConfig<TYPES>> {
225 membership.da_stake(pub_key)
226 }
227
228 fn stake_table(membership: &EpochMembership<TYPES>) -> HSStakeTable<TYPES> {
230 membership.da_stake_table().collect()
231 }
232
233 fn total_nodes(membership: &EpochMembership<TYPES>) -> usize {
235 membership.da_total_nodes()
236 }
237
238 fn threshold(membership: &EpochMembership<TYPES>) -> U256 {
239 membership.da_success_threshold()
240 }
241
242 fn data(&self) -> &Self::Voteable {
243 &self.data
244 }
245
246 fn data_commitment(
247 &self,
248 upgrade_lock: &UpgradeLock<TYPES>,
249 ) -> Result<Commitment<VersionedVoteData<TYPES, DaData>>> {
250 Ok(VersionedVoteData::new(self.data.clone(), self.view_number, upgrade_lock)?.commit())
251 }
252}
253
254impl<TYPES: NodeType, THRESHOLD: Threshold<TYPES>> Certificate<TYPES, DaData2>
255 for SimpleCertificate<TYPES, DaData2, THRESHOLD>
256{
257 type Voteable = DaData2;
258 type Threshold = THRESHOLD;
259
260 fn create_signed_certificate(
261 vote_commitment: Commitment<VersionedVoteData<TYPES, DaData2>>,
262 data: Self::Voteable,
263 sig: <TYPES::SignatureKey as SignatureKey>::QcType,
264 view: ViewNumber,
265 ) -> Self {
266 let vote_commitment_bytes: [u8; 32] = vote_commitment.into();
267
268 SimpleCertificate {
269 data,
270 vote_commitment: Commitment::from_raw(vote_commitment_bytes),
271 view_number: view,
272 signatures: Some(sig),
273 _pd: PhantomData,
274 }
275 }
276 fn is_valid_cert(
277 &self,
278 stake_table: &[<TYPES::SignatureKey as SignatureKey>::StakeTableEntry],
279 threshold: U256,
280 upgrade_lock: &UpgradeLock<TYPES>,
281 ) -> Result<()> {
282 if self.view_number == ViewNumber::genesis() {
283 return Ok(());
284 }
285 let real_qc_pp =
286 <TYPES::SignatureKey as SignatureKey>::public_parameter(stake_table, threshold);
287 let commit = self.data_commitment(upgrade_lock)?;
288 let signatures = self
289 .signatures
290 .as_ref()
291 .ok_or_else(|| warn!("missing signatures"))?;
292
293 <TYPES::SignatureKey as SignatureKey>::check(&real_qc_pp, commit.as_ref(), signatures)
294 .wrap()
295 .context(|e| warn!("Signature check failed: {e}"))
296 }
297 fn signers(
298 &self,
299 stake_table: &[<TYPES::SignatureKey as SignatureKey>::StakeTableEntry],
300 threshold: U256,
301 ) -> Result<Vec<<TYPES::SignatureKey as SignatureKey>::VerificationKeyType>> {
302 self.signers(stake_table, threshold)
303 }
304 fn stake_table_entry(
306 membership: &EpochMembership<TYPES>,
307 pub_key: &TYPES::SignatureKey,
308 ) -> Option<PeerConfig<TYPES>> {
309 membership.da_stake(pub_key)
310 }
311
312 fn stake_table(membership: &EpochMembership<TYPES>) -> HSStakeTable<TYPES> {
314 membership.da_stake_table().collect()
315 }
316
317 fn total_nodes(membership: &EpochMembership<TYPES>) -> usize {
319 membership.da_total_nodes()
320 }
321
322 fn threshold(membership: &EpochMembership<TYPES>) -> U256 {
323 membership.da_success_threshold()
324 }
325
326 fn data(&self) -> &Self::Voteable {
327 &self.data
328 }
329
330 fn data_commitment(
331 &self,
332 upgrade_lock: &UpgradeLock<TYPES>,
333 ) -> Result<Commitment<VersionedVoteData<TYPES, DaData2>>> {
334 Ok(VersionedVoteData::new(self.data.clone(), self.view_number, upgrade_lock)?.commit())
335 }
336}
337
338impl<
339 TYPES: NodeType,
340 VOTEABLE: Voteable<TYPES> + 'static + QuorumMarker,
341 THRESHOLD: Threshold<TYPES>,
342> Certificate<TYPES, VOTEABLE> for SimpleCertificate<TYPES, VOTEABLE, THRESHOLD>
343{
344 type Voteable = VOTEABLE;
345 type Threshold = THRESHOLD;
346
347 fn create_signed_certificate(
348 vote_commitment: Commitment<VersionedVoteData<TYPES, VOTEABLE>>,
349 data: Self::Voteable,
350 sig: <TYPES::SignatureKey as SignatureKey>::QcType,
351 view: ViewNumber,
352 ) -> Self {
353 let vote_commitment_bytes: [u8; 32] = vote_commitment.into();
354
355 SimpleCertificate {
356 data,
357 vote_commitment: Commitment::from_raw(vote_commitment_bytes),
358 view_number: view,
359 signatures: Some(sig),
360 _pd: PhantomData,
361 }
362 }
363
364 fn is_valid_cert(
365 &self,
366 stake_table: &[<TYPES::SignatureKey as SignatureKey>::StakeTableEntry],
367 threshold: U256,
368 upgrade_lock: &UpgradeLock<TYPES>,
369 ) -> Result<()> {
370 if self.view_number == ViewNumber::genesis() {
371 return Ok(());
372 }
373 let real_qc_pp =
374 <TYPES::SignatureKey as SignatureKey>::public_parameter(stake_table, threshold);
375 let commit = self.data_commitment(upgrade_lock)?;
376 let signatures = self
377 .signatures
378 .as_ref()
379 .ok_or_else(|| warn!("missing signatures"))?;
380
381 <TYPES::SignatureKey as SignatureKey>::check(&real_qc_pp, commit.as_ref(), signatures)
382 .wrap()
383 .context(|e| warn!("Signature check failed: {e}"))
384 }
385
386 fn signers(
387 &self,
388 stake_table: &[<TYPES::SignatureKey as SignatureKey>::StakeTableEntry],
389 threshold: U256,
390 ) -> Result<Vec<<TYPES::SignatureKey as SignatureKey>::VerificationKeyType>> {
391 self.signers(stake_table, threshold)
392 }
393
394 fn threshold(membership: &EpochMembership<TYPES>) -> U256 {
395 THRESHOLD::threshold(membership)
396 }
397
398 fn stake_table_entry(
399 membership: &EpochMembership<TYPES>,
400 pub_key: &TYPES::SignatureKey,
401 ) -> Option<PeerConfig<TYPES>> {
402 membership.stake(pub_key)
403 }
404
405 fn stake_table(membership: &EpochMembership<TYPES>) -> HSStakeTable<TYPES> {
406 membership.stake_table().collect()
407 }
408
409 fn total_nodes(membership: &EpochMembership<TYPES>) -> usize {
411 membership.total_nodes()
412 }
413
414 fn data(&self) -> &Self::Voteable {
415 &self.data
416 }
417 fn data_commitment(
418 &self,
419 upgrade_lock: &UpgradeLock<TYPES>,
420 ) -> Result<Commitment<VersionedVoteData<TYPES, VOTEABLE>>> {
421 Ok(VersionedVoteData::new(self.data.clone(), self.view_number, upgrade_lock)?.commit())
422 }
423}
424
425impl<TYPES: NodeType, VOTEABLE: Voteable<TYPES> + 'static, THRESHOLD: Threshold<TYPES>>
426 HasViewNumber for SimpleCertificate<TYPES, VOTEABLE, THRESHOLD>
427{
428 fn view_number(&self) -> ViewNumber {
429 self.view_number
430 }
431}
432
433impl<TYPES: NodeType, VOTEABLE: Voteable<TYPES> + HasEpoch + 'static, THRESHOLD: Threshold<TYPES>>
434 HasEpoch for SimpleCertificate<TYPES, VOTEABLE, THRESHOLD>
435{
436 fn epoch(&self) -> Option<EpochNumber> {
437 self.data.epoch()
438 }
439}
440
441impl<TYPES: NodeType> Display for QuorumCertificate<TYPES> {
442 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
443 write!(f, "view: {:?}", self.view_number)
444 }
445}
446
447impl<TYPES: NodeType> UpgradeCertificate<TYPES> {
448 pub async fn is_relevant(&self, view_number: ViewNumber) -> Result<()> {
454 ensure!(
455 self.data.new_version_first_view >= view_number,
456 "Upgrade certificate is no longer relevant."
457 );
458
459 Ok(())
460 }
461
462 pub async fn validate(
466 upgrade_certificate: &Option<Self>,
467 membership: &EpochMembership<TYPES>,
468 epoch: Option<EpochNumber>,
469 upgrade_lock: &UpgradeLock<TYPES>,
470 ) -> Result<()> {
471 ensure!(epoch == membership.epoch(), "Epochs don't match!");
472 if let Some(cert) = upgrade_certificate {
473 let membership_stake_table = membership.stake_table();
474 let membership_upgrade_threshold = membership.upgrade_threshold();
475
476 cert.is_valid_cert(
477 &StakeTableEntries::from_iter(membership_stake_table).0,
478 membership_upgrade_threshold,
479 upgrade_lock,
480 )
481 .context(|e| warn!("Invalid upgrade certificate: {e}"))?;
482 }
483
484 Ok(())
485 }
486
487 pub fn upgrading_in(&self, view: ViewNumber) -> bool {
490 view > self.data.old_version_last_view && view < self.data.new_version_first_view
491 }
492}
493
494impl<TYPES: NodeType> QuorumCertificate<TYPES> {
495 pub fn to_qc2(self) -> QuorumCertificate2<TYPES> {
497 let bytes: [u8; 32] = self.data.leaf_commit.into();
498 let data = QuorumData2 {
499 leaf_commit: Commitment::from_raw(bytes),
500 epoch: None,
501 block_number: None,
502 };
503
504 let bytes: [u8; 32] = self.vote_commitment.into();
505 let vote_commitment = Commitment::from_raw(bytes);
506
507 SimpleCertificate {
508 data,
509 vote_commitment,
510 view_number: self.view_number,
511 signatures: self.signatures.clone(),
512 _pd: PhantomData,
513 }
514 }
515}
516
517impl<TYPES: NodeType> QuorumCertificate2<TYPES> {
518 pub fn to_qc(self) -> QuorumCertificate<TYPES> {
520 let bytes: [u8; 32] = self.data.leaf_commit.into();
521 let data = QuorumData {
522 leaf_commit: Commitment::from_raw(bytes),
523 };
524
525 let bytes: [u8; 32] = self.vote_commitment.into();
526 let vote_commitment = Commitment::from_raw(bytes);
527
528 SimpleCertificate {
529 data,
530 vote_commitment,
531 view_number: self.view_number,
532 signatures: self.signatures.clone(),
533 _pd: PhantomData,
534 }
535 }
536}
537
538impl<TYPES: NodeType> DaCertificate<TYPES> {
539 pub fn to_dac2(self) -> DaCertificate2<TYPES> {
541 let data = DaData2 {
542 payload_commit: self.data.payload_commit,
543 next_epoch_payload_commit: None,
544 epoch: None,
545 };
546
547 let bytes: [u8; 32] = self.vote_commitment.into();
548 let vote_commitment = Commitment::from_raw(bytes);
549
550 SimpleCertificate {
551 data,
552 vote_commitment,
553 view_number: self.view_number,
554 signatures: self.signatures.clone(),
555 _pd: PhantomData,
556 }
557 }
558}
559
560impl<TYPES: NodeType> DaCertificate2<TYPES> {
561 pub fn to_dac(self) -> DaCertificate<TYPES> {
563 let data = DaData {
564 payload_commit: self.data.payload_commit,
565 };
566
567 let bytes: [u8; 32] = self.vote_commitment.into();
568 let vote_commitment = Commitment::from_raw(bytes);
569
570 SimpleCertificate {
571 data,
572 vote_commitment,
573 view_number: self.view_number,
574 signatures: self.signatures.clone(),
575 _pd: PhantomData,
576 }
577 }
578}
579
580impl<TYPES: NodeType> ViewSyncPreCommitCertificate<TYPES> {
581 pub fn to_vsc2(self) -> ViewSyncPreCommitCertificate2<TYPES> {
583 let data = ViewSyncPreCommitData2 {
584 relay: self.data.relay,
585 round: self.data.round,
586 epoch: None,
587 };
588
589 let bytes: [u8; 32] = self.vote_commitment.into();
590 let vote_commitment = Commitment::from_raw(bytes);
591
592 SimpleCertificate {
593 data,
594 vote_commitment,
595 view_number: self.view_number,
596 signatures: self.signatures.clone(),
597 _pd: PhantomData,
598 }
599 }
600}
601
602impl<TYPES: NodeType> ViewSyncCommitCertificate<TYPES> {
603 pub fn to_vsc2(self) -> ViewSyncCommitCertificate2<TYPES> {
605 let data = ViewSyncCommitData2 {
606 relay: self.data.relay,
607 round: self.data.round,
608 epoch: None,
609 };
610
611 let bytes: [u8; 32] = self.vote_commitment.into();
612 let vote_commitment = Commitment::from_raw(bytes);
613
614 SimpleCertificate {
615 data,
616 vote_commitment,
617 view_number: self.view_number,
618 signatures: self.signatures.clone(),
619 _pd: PhantomData,
620 }
621 }
622}
623
624impl<TYPES: NodeType> ViewSyncFinalizeCertificate<TYPES> {
625 pub fn to_vsc2(self) -> ViewSyncFinalizeCertificate2<TYPES> {
627 let data = ViewSyncFinalizeData2 {
628 relay: self.data.relay,
629 round: self.data.round,
630 epoch: None,
631 };
632
633 let bytes: [u8; 32] = self.vote_commitment.into();
634 let vote_commitment = Commitment::from_raw(bytes);
635
636 SimpleCertificate {
637 data,
638 vote_commitment,
639 view_number: self.view_number,
640 signatures: self.signatures.clone(),
641 _pd: PhantomData,
642 }
643 }
644}
645
646impl<TYPES: NodeType> TimeoutCertificate<TYPES> {
647 pub fn to_tc2(self) -> TimeoutCertificate2<TYPES> {
649 let data = TimeoutData2 {
650 view: self.data.view,
651 epoch: None,
652 };
653
654 let bytes: [u8; 32] = self.vote_commitment.into();
655 let vote_commitment = Commitment::from_raw(bytes);
656
657 SimpleCertificate {
658 data,
659 vote_commitment,
660 view_number: self.view_number,
661 signatures: self.signatures.clone(),
662 _pd: PhantomData,
663 }
664 }
665}
666
667#[derive(derive_more::Debug, Clone, Eq, PartialEq, Hash)]
669pub enum TimeoutEvidence<T: NodeType> {
670 V2(TimeoutCertificate2<T>),
671 V3(TimeoutCertificate3<T>),
672}
673
674impl<T: NodeType> TimeoutEvidence<T> {
675 pub fn binds_epoch(&self) -> bool {
676 matches!(self, Self::V3(_))
677 }
678
679 pub fn lock(&self) -> Option<(LockView, &QuorumCertificate2<T>)> {
684 match self {
685 Self::V2(_) => None,
686 Self::V3(cert) => cert.lock_cert().map(|cert| (LockView::of(cert), cert)),
687 }
688 }
689
690 pub fn timeout_lock(&self) -> TimeoutLock<'_, T> {
693 match self {
694 Self::V2(_) => TimeoutLock::None,
695 Self::V3(cert) => cert.timeout_lock(),
696 }
697 }
698
699 pub fn is_valid_cert(
704 &self,
705 stake_table: &[<T::SignatureKey as SignatureKey>::StakeTableEntry],
706 threshold: U256,
707 upgrade_lock: &UpgradeLock<T>,
708 ) -> Result<()> {
709 let view = self.view_number();
710 match self {
711 Self::V2(cert) => {
712 ensure! {
713 !upgrade_lock.timeout_epoch_bound(view),
714 "timeout certificate for view {} must not bind its epoch", view
715 }
716 ensure! {
717 view == cert.data.view,
718 "timeout certificate view {} != data view {}", view, cert.data.view
719 }
720 cert.is_valid_cert(stake_table, threshold, upgrade_lock)
721 },
722 Self::V3(cert) => {
727 ensure! {
728 upgrade_lock.timeout_epoch_bound(view),
729 "timeout certificate for view {} must bind its epoch", view
730 }
731 cert.check_signatures(stake_table, threshold, upgrade_lock)
732 },
733 }
734 }
735}
736
737impl<T: NodeType> HasViewNumber for TimeoutEvidence<T> {
738 fn view_number(&self) -> ViewNumber {
739 match self {
740 Self::V2(c) => c.view_number,
741 Self::V3(c) => c.view_number,
742 }
743 }
744}
745
746impl<T: NodeType> HasEpoch for TimeoutEvidence<T> {
747 fn epoch(&self) -> Option<EpochNumber> {
748 match self {
749 Self::V2(cert) => cert.data.epoch,
750 Self::V3(cert) => Some(cert.epoch),
751 }
752 }
753}
754
755pub mod optional_timeout_evidence {
756 use super::*;
757
758 pub fn serialize<T: NodeType, S: Serializer>(
759 evidence: &Option<TimeoutEvidence<T>>,
760 s: S,
761 ) -> std::result::Result<S::Ok, S::Error> {
762 if s.is_human_readable() {
763 return match evidence {
764 None => s.serialize_none(),
765 Some(TimeoutEvidence::V2(cert)) => s.serialize_some(cert),
766 Some(TimeoutEvidence::V3(cert)) => s.serialize_some(&HumanReadableV3 {
767 cert: Cow::Borrowed(cert),
768 }),
769 };
770 }
771
772 let mut t = s.serialize_tuple(2)?;
773 match evidence {
774 None => {
775 t.serialize_element(&0u8)?;
776 t.serialize_element(&())?;
777 },
778 Some(TimeoutEvidence::V2(cert)) => {
779 t.serialize_element(&1u8)?;
780 t.serialize_element(cert)?;
781 },
782 Some(TimeoutEvidence::V3(cert)) => {
783 t.serialize_element(&2u8)?;
784 t.serialize_element(cert)?;
785 },
786 }
787 t.end()
788 }
789
790 pub fn deserialize<'de, T: NodeType, D: Deserializer<'de>>(
791 d: D,
792 ) -> std::result::Result<Option<TimeoutEvidence<T>>, D::Error> {
793 if d.is_human_readable() {
794 return Ok(match Option::<HumanReadable<T>>::deserialize(d)? {
795 None => None,
796 Some(HumanReadable::V3(tagged)) => {
797 Some(TimeoutEvidence::V3(tagged.cert.into_owned()))
798 },
799 Some(HumanReadable::V2(cert)) => Some(TimeoutEvidence::V2(cert)),
800 });
801 }
802
803 d.deserialize_tuple(2, EvidenceVisitor(PhantomData))
804 }
805
806 #[derive(Deserialize)]
807 #[serde(untagged, bound(deserialize = ""))]
808 enum HumanReadable<T: NodeType> {
809 V3(HumanReadableV3<'static, T>),
810 V2(TimeoutCertificate2<T>),
811 }
812
813 #[derive(Serialize, Deserialize)]
814 #[serde(bound(deserialize = ""))]
815 struct HumanReadableV3<'a, T: NodeType> {
816 #[serde(rename = "V3")]
817 cert: Cow<'a, TimeoutCertificate3<T>>,
818 }
819
820 struct EvidenceVisitor<T: NodeType>(PhantomData<T>);
821
822 impl<'de, T: NodeType> Visitor<'de> for EvidenceVisitor<T> {
823 type Value = Option<TimeoutEvidence<T>>;
824
825 fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
826 write!(f, "a timeout evidence discriminant followed by its payload")
827 }
828
829 fn visit_seq<A: SeqAccess<'de>>(
830 self,
831 mut seq: A,
832 ) -> std::result::Result<Self::Value, A::Error> {
833 let missing = |field| de::Error::custom(format!("missing {field}"));
834 let tag: u8 = seq
835 .next_element()?
836 .ok_or_else(|| missing("timeout evidence discriminant"))?;
837 match tag {
838 0 => {
839 seq.next_element::<()>()?;
840 Ok(None)
841 },
842 1 => Ok(Some(TimeoutEvidence::V2(
843 seq.next_element()?
844 .ok_or_else(|| missing("timeout certificate"))?,
845 ))),
846 2 => Ok(Some(TimeoutEvidence::V3(
847 seq.next_element()?
848 .ok_or_else(|| missing("timeout certificate"))?,
849 ))),
850 other => Err(de::Error::custom(format!(
851 "invalid timeout evidence discriminant {other}"
852 ))),
853 }
854 }
855 }
856}
857
858pub type QuorumCertificate<TYPES> = SimpleCertificate<TYPES, QuorumData<TYPES>, SuccessThreshold>;
860pub type QuorumCertificate2<TYPES> = SimpleCertificate<TYPES, QuorumData2<TYPES>, SuccessThreshold>;
862pub type NextEpochQuorumCertificate2<TYPES> =
864 SimpleCertificate<TYPES, NextEpochQuorumData2<TYPES>, SuccessThreshold>;
865pub type Certificate1<TYPES> = SimpleCertificate<TYPES, QuorumData2<TYPES>, SuccessThreshold>;
867pub type Certificate2<TYPES> = SimpleCertificate<TYPES, Vote2Data<TYPES>, SuccessThreshold>;
869pub type DaCertificate<TYPES> = SimpleCertificate<TYPES, DaData, SuccessThreshold>;
871pub type DaCertificate2<TYPES> = SimpleCertificate<TYPES, DaData2, SuccessThreshold>;
873pub type TimeoutCertificate<TYPES> = SimpleCertificate<TYPES, TimeoutData, SuccessThreshold>;
875pub type TimeoutCertificate2<TYPES> = SimpleCertificate<TYPES, TimeoutData2, SuccessThreshold>;
877pub type ViewSyncPreCommitCertificate<TYPES> =
879 SimpleCertificate<TYPES, ViewSyncPreCommitData, OneHonestThreshold>;
880pub type ViewSyncPreCommitCertificate2<TYPES> =
882 SimpleCertificate<TYPES, ViewSyncPreCommitData2, OneHonestThreshold>;
883pub type ViewSyncCommitCertificate<TYPES> =
885 SimpleCertificate<TYPES, ViewSyncCommitData, SuccessThreshold>;
886pub type ViewSyncCommitCertificate2<TYPES> =
888 SimpleCertificate<TYPES, ViewSyncCommitData2, SuccessThreshold>;
889pub type ViewSyncFinalizeCertificate<TYPES> =
891 SimpleCertificate<TYPES, ViewSyncFinalizeData, SuccessThreshold>;
892pub type ViewSyncFinalizeCertificate2<TYPES> =
894 SimpleCertificate<TYPES, ViewSyncFinalizeData2, SuccessThreshold>;
895pub type UpgradeCertificate<TYPES> =
897 SimpleCertificate<TYPES, UpgradeProposalData, UpgradeThreshold>;
898pub type UpgradeCertificate2<TYPES> =
901 SimpleCertificate<TYPES, UpgradeProposalData2, UpgradeThreshold>;
902
903impl<TYPES: NodeType> UpgradeCertificate2<TYPES> {
904 pub fn strip_epoch(self) -> UpgradeCertificate<TYPES> {
909 let vote_commitment: [u8; 32] = self.vote_commitment.into();
910 UpgradeCertificate::new(
911 self.data.strip_epoch(),
912 Commitment::from_raw(vote_commitment),
913 self.view_number,
914 self.signatures,
915 PhantomData,
916 )
917 }
918
919 pub fn restore_epoch(cert: UpgradeCertificate<TYPES>, epoch: EpochNumber) -> Self {
922 let vote_commitment: [u8; 32] = cert.vote_commitment.into();
923 Self::new(
924 UpgradeProposalData2::restore_epoch(cert.data, epoch),
925 Commitment::from_raw(vote_commitment),
926 cert.view_number,
927 cert.signatures,
928 PhantomData,
929 )
930 }
931}
932
933#[derive(Serialize, Deserialize, Eq, Hash, PartialEq, Debug, Clone)]
935pub struct LightClientStateUpdateCertificateV2<TYPES: NodeType> {
936 pub epoch: EpochNumber,
938 pub light_client_state: LightClientState,
940 pub next_stake_table_state: StakeTableState,
942 #[allow(clippy::type_complexity)]
944 pub signatures: Vec<(
945 TYPES::StateSignatureKey,
946 <TYPES::StateSignatureKey as StateSignatureKey>::StateSignature, <TYPES::StateSignatureKey as StateSignatureKey>::StateSignature, )>,
949 pub auth_root: FixedBytes<32>,
954}
955
956#[derive(Serialize, Deserialize, Eq, Hash, PartialEq, Debug, Clone)]
958pub struct LightClientStateUpdateCertificateV1<TYPES: NodeType> {
959 pub epoch: EpochNumber,
961 pub light_client_state: LightClientState,
963 pub next_stake_table_state: StakeTableState,
965 pub signatures: Vec<(
967 TYPES::StateSignatureKey,
968 <TYPES::StateSignatureKey as StateSignatureKey>::StateSignature,
969 )>,
970}
971
972impl<TYPES: NodeType> From<LightClientStateUpdateCertificateV1<TYPES>>
973 for LightClientStateUpdateCertificateV2<TYPES>
974{
975 fn from(v1: LightClientStateUpdateCertificateV1<TYPES>) -> Self {
976 Self {
977 epoch: v1.epoch,
978 light_client_state: v1.light_client_state,
979 next_stake_table_state: v1.next_stake_table_state,
980 signatures: v1
981 .signatures
982 .into_iter()
983 .map(|(key, sig)| (key, sig.clone(), sig)) .collect(),
985 auth_root: Default::default(),
986 }
987 }
988}
989
990impl<TYPES: NodeType> From<LightClientStateUpdateCertificateV2<TYPES>>
991 for LightClientStateUpdateCertificateV1<TYPES>
992{
993 fn from(v2: LightClientStateUpdateCertificateV2<TYPES>) -> Self {
994 Self {
995 epoch: v2.epoch,
996 light_client_state: v2.light_client_state,
997 next_stake_table_state: v2.next_stake_table_state,
998 signatures: v2
999 .signatures
1000 .into_iter()
1001 .map(|(key, _, sig)| (key, sig))
1002 .collect(),
1003 }
1004 }
1005}
1006
1007impl<TYPES: NodeType> HasViewNumber for LightClientStateUpdateCertificateV2<TYPES> {
1008 fn view_number(&self) -> ViewNumber {
1009 ViewNumber::new(self.light_client_state.view_number)
1010 }
1011}
1012
1013impl<TYPES: NodeType> HasEpoch for LightClientStateUpdateCertificateV2<TYPES> {
1014 fn epoch(&self) -> Option<EpochNumber> {
1015 Some(self.epoch)
1016 }
1017}
1018
1019impl<TYPES: NodeType> LightClientStateUpdateCertificateV1<TYPES> {
1020 pub fn genesis() -> Self {
1021 Self {
1022 epoch: EpochNumber::genesis(),
1023 light_client_state: Default::default(),
1024 next_stake_table_state: Default::default(),
1025 signatures: vec![],
1026 }
1027 }
1028}
1029
1030impl<TYPES: NodeType> LightClientStateUpdateCertificateV2<TYPES> {
1031 pub fn genesis() -> Self {
1032 Self {
1033 epoch: EpochNumber::genesis(),
1034 light_client_state: Default::default(),
1035 next_stake_table_state: Default::default(),
1036 signatures: vec![],
1037 auth_root: Default::default(),
1038 }
1039 }
1040}
1041
1042#[derive(Serialize, Deserialize, Eq, Hash, PartialEq, Debug, Clone)]
1043#[serde(bound(deserialize = "QuorumCertificate2<TYPES>:for<'a> Deserialize<'a>"))]
1044pub struct EpochRootQuorumCertificateV2<TYPES: NodeType> {
1045 pub qc: QuorumCertificate2<TYPES>,
1046 pub state_cert: LightClientStateUpdateCertificateV2<TYPES>,
1047}
1048
1049impl<TYPES: NodeType> HasViewNumber for EpochRootQuorumCertificateV2<TYPES> {
1050 fn view_number(&self) -> ViewNumber {
1051 self.qc.view_number()
1052 }
1053}
1054
1055impl<TYPES: NodeType> HasEpoch for EpochRootQuorumCertificateV2<TYPES> {
1056 fn epoch(&self) -> Option<EpochNumber> {
1057 self.qc.epoch()
1058 }
1059}
1060
1061#[derive(Serialize, Deserialize, Eq, Hash, PartialEq, Debug, Clone)]
1062#[serde(bound(deserialize = "QuorumCertificate2<TYPES>:for<'a> Deserialize<'a>"))]
1063pub struct EpochRootQuorumCertificateV1<TYPES: NodeType> {
1064 pub qc: QuorumCertificate2<TYPES>,
1065 pub state_cert: LightClientStateUpdateCertificateV1<TYPES>,
1066}
1067
1068impl<TYPES: NodeType> HasViewNumber for EpochRootQuorumCertificateV1<TYPES> {
1069 fn view_number(&self) -> ViewNumber {
1070 self.qc.view_number()
1071 }
1072}
1073
1074impl<TYPES: NodeType> HasEpoch for EpochRootQuorumCertificateV1<TYPES> {
1075 fn epoch(&self) -> Option<EpochNumber> {
1076 self.qc.epoch()
1077 }
1078}
1079
1080impl<TYPES: NodeType> From<EpochRootQuorumCertificateV1<TYPES>>
1081 for EpochRootQuorumCertificateV2<TYPES>
1082{
1083 fn from(root_qc: EpochRootQuorumCertificateV1<TYPES>) -> Self {
1084 Self {
1085 qc: root_qc.qc,
1086 state_cert: root_qc.state_cert.into(),
1087 }
1088 }
1089}
1090
1091impl<TYPES: NodeType> From<EpochRootQuorumCertificateV2<TYPES>>
1092 for EpochRootQuorumCertificateV1<TYPES>
1093{
1094 fn from(root_qc: EpochRootQuorumCertificateV2<TYPES>) -> Self {
1095 Self {
1096 qc: root_qc.qc,
1097 state_cert: root_qc.state_cert.into(),
1098 }
1099 }
1100}
1101
1102#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
1108#[serde(bound = "")]
1109pub struct CertificatePair<TYPES: NodeType> {
1110 qc: QuorumCertificate2<TYPES>,
1112
1113 next_epoch_qc: Option<NextEpochQuorumCertificate2<TYPES>>,
1115}
1116
1117impl<TYPES: NodeType> CertificatePair<TYPES> {
1118 pub fn new(
1120 qc: QuorumCertificate2<TYPES>,
1121 next_epoch_qc: Option<NextEpochQuorumCertificate2<TYPES>>,
1122 ) -> Self {
1123 Self { qc, next_epoch_qc }
1124 }
1125
1126 pub fn non_epoch_change(qc: QuorumCertificate2<TYPES>) -> Self {
1128 Self::new(qc, None)
1129 }
1130
1131 pub fn for_parent(leaf: &Leaf2<TYPES>) -> Self {
1133 Self {
1134 qc: leaf.justify_qc().clone(),
1135 next_epoch_qc: leaf.next_epoch_justify_qc().cloned(),
1136 }
1137 }
1138
1139 pub fn qc(&self) -> &QuorumCertificate2<TYPES> {
1141 &self.qc
1142 }
1143
1144 pub fn next_epoch_qc(&self) -> Option<&NextEpochQuorumCertificate2<TYPES>> {
1146 self.next_epoch_qc.as_ref()
1147 }
1148
1149 pub fn leaf_commit(&self) -> Commitment<Leaf2<TYPES>> {
1151 self.qc.data.leaf_commit
1152 }
1153
1154 pub fn epoch(&self) -> Option<EpochNumber> {
1158 self.qc.data.epoch
1159 }
1160
1161 pub fn block_number(&self) -> Option<u64> {
1165 self.qc.data.block_number
1166 }
1167
1168 pub fn verify_next_epoch_qc(
1178 &self,
1179 epoch_height: u64,
1180 ) -> Result<Option<&NextEpochQuorumCertificate2<TYPES>>> {
1181 let block_number = self.qc.data.block_number.context(warn!(
1182 "QC for epoch {:?} has no block number",
1183 self.qc.data.epoch
1184 ))?;
1185 if !is_epoch_transition(block_number, epoch_height) {
1186 tracing::debug!(
1187 block_number,
1188 epoch_height,
1189 "QC is not in an epoch transition"
1190 );
1191 return Ok(None);
1192 }
1193
1194 let next_epoch_qc = self.next_epoch_qc.as_ref().context(warn!(
1195 "Received High QC for the transition block {block_number} but not the next epoch QC"
1196 ))?;
1197
1198 ensure!(self.qc.view_number == next_epoch_qc.view_number);
1200 ensure!(self.qc.data == *next_epoch_qc.data);
1201
1202 Ok(Some(next_epoch_qc))
1203 }
1204}
1205
1206impl<TYPES: NodeType> HasViewNumber for CertificatePair<TYPES> {
1207 fn view_number(&self) -> ViewNumber {
1208 self.qc.view_number()
1209 }
1210}
1211
1212pub fn check_qc_state_cert_correspondence<TYPES: NodeType>(
1215 qc: &QuorumCertificate2<TYPES>,
1216 state_cert: &LightClientStateUpdateCertificateV2<TYPES>,
1217 epoch_height: u64,
1218) -> bool {
1219 qc.data
1220 .block_number
1221 .is_some_and(|bn| is_epoch_root(bn, epoch_height))
1222 && Some(state_cert.epoch) == qc.data.epoch()
1223 && qc.view_number().u64() == state_cert.light_client_state.view_number
1224}