1use std::{
10 fmt::{self, Debug, Display, Formatter},
11 future::Future,
12 hash::Hash,
13 marker::PhantomData,
14};
15
16use alloy::primitives::{FixedBytes, U256};
17use committable::{Commitment, Committable};
18use hotshot_utils::anytrace::*;
19use serde::{Deserialize, Serialize};
20
21use crate::{
22 PeerConfig,
23 data::{EpochNumber, Leaf2, ViewNumber, serialize_signature2},
24 epoch_membership::EpochMembership,
25 light_client::{LightClientState, StakeTableState},
26 message::UpgradeLock,
27 simple_vote::{
28 DaData, DaData2, HasEpoch, NextEpochQuorumData2, QuorumData, QuorumData2, QuorumMarker,
29 TimeoutData, TimeoutData2, UpgradeProposalData, VersionedVoteData, ViewSyncCommitData,
30 ViewSyncCommitData2, ViewSyncFinalizeData, ViewSyncFinalizeData2, ViewSyncPreCommitData,
31 ViewSyncPreCommitData2, Voteable,
32 },
33 stake_table::{HSStakeTable, StakeTableEntries},
34 traits::{
35 node_implementation::NodeType,
36 signature_key::{SignatureKey, StateSignatureKey},
37 },
38 utils::is_epoch_transition,
39 vote::{Certificate, HasViewNumber},
40};
41
42pub trait Threshold<TYPES: NodeType> {
44 fn threshold(membership: &EpochMembership<TYPES>) -> impl Future<Output = U256> + Send;
46}
47
48#[derive(Serialize, Deserialize, Eq, Hash, PartialEq, Debug, Clone)]
50pub struct SuccessThreshold {}
51
52impl<TYPES: NodeType> Threshold<TYPES> for SuccessThreshold {
53 async fn threshold(membership: &EpochMembership<TYPES>) -> U256 {
54 membership.success_threshold().await
55 }
56}
57
58#[derive(Serialize, Deserialize, Eq, Hash, PartialEq, Debug, Clone)]
60pub struct OneHonestThreshold {}
61
62impl<TYPES: NodeType> Threshold<TYPES> for OneHonestThreshold {
63 async fn threshold(membership: &EpochMembership<TYPES>) -> U256 {
64 membership.failure_threshold().await
65 }
66}
67
68#[derive(Serialize, Deserialize, Eq, Hash, PartialEq, Debug, Clone)]
70pub struct UpgradeThreshold {}
71
72impl<TYPES: NodeType> Threshold<TYPES> for UpgradeThreshold {
73 async fn threshold(membership: &EpochMembership<TYPES>) -> U256 {
74 membership.upgrade_threshold().await
75 }
76}
77
78#[derive(Serialize, Deserialize, Eq, Hash, PartialEq, Debug, Clone)]
80pub struct SimpleCertificate<
81 TYPES: NodeType,
82 VOTEABLE: Voteable<TYPES>,
83 THRESHOLD: Threshold<TYPES>,
84> {
85 pub data: VOTEABLE,
87 vote_commitment: Commitment<VOTEABLE>,
89 pub view_number: ViewNumber,
91 pub signatures: Option<<TYPES::SignatureKey as SignatureKey>::QcType>,
93 pub _pd: PhantomData<(TYPES, THRESHOLD)>,
95}
96
97impl<TYPES: NodeType, VOTEABLE: Voteable<TYPES>, THRESHOLD: Threshold<TYPES>>
98 SimpleCertificate<TYPES, VOTEABLE, THRESHOLD>
99{
100 pub fn new(
102 data: VOTEABLE,
103 vote_commitment: Commitment<VOTEABLE>,
104 view_number: ViewNumber,
105 signatures: Option<<TYPES::SignatureKey as SignatureKey>::QcType>,
106 pd: PhantomData<(TYPES, THRESHOLD)>,
107 ) -> Self {
108 Self {
109 data,
110 vote_commitment,
111 view_number,
112 signatures,
113 _pd: pd,
114 }
115 }
116
117 fn signers(
118 &self,
119 stake_table: &[<TYPES::SignatureKey as SignatureKey>::StakeTableEntry],
120 threshold: U256,
121 ) -> Result<Vec<<TYPES::SignatureKey as SignatureKey>::VerificationKeyType>> {
122 if self.view_number == ViewNumber::genesis() {
123 return Ok(vec![]);
124 }
125 let real_qc_pp =
126 <TYPES::SignatureKey as SignatureKey>::public_parameter(stake_table, threshold);
127
128 let Some(ref signatures) = self.signatures else {
129 bail!("No signatures found while retrieving signers");
130 };
131
132 <TYPES::SignatureKey as SignatureKey>::signers(&real_qc_pp, signatures)
133 .wrap()
134 .context(|e| warn!("Tracing signers: {e}"))
135 }
136}
137
138impl<TYPES: NodeType, VOTEABLE: Voteable<TYPES> + Committable, THRESHOLD: Threshold<TYPES>>
139 Committable for SimpleCertificate<TYPES, VOTEABLE, THRESHOLD>
140{
141 fn commit(&self) -> Commitment<Self> {
142 let signature_bytes = match self.signatures.as_ref() {
143 Some(sigs) => serialize_signature2::<TYPES>(sigs),
144 None => vec![],
145 };
146 committable::RawCommitmentBuilder::new("Certificate")
147 .field("data", self.data.commit())
148 .field("vote_commitment", self.vote_commitment)
149 .field("view number", self.view_number.commit())
150 .var_size_field("signatures", &signature_bytes)
151 .finalize()
152 }
153}
154
155impl<TYPES: NodeType, THRESHOLD: Threshold<TYPES>> Certificate<TYPES, DaData>
156 for SimpleCertificate<TYPES, DaData, THRESHOLD>
157{
158 type Voteable = DaData;
159 type Threshold = THRESHOLD;
160
161 fn create_signed_certificate(
162 vote_commitment: Commitment<VersionedVoteData<TYPES, DaData>>,
163 data: Self::Voteable,
164 sig: <TYPES::SignatureKey as SignatureKey>::QcType,
165 view: ViewNumber,
166 ) -> Self {
167 let vote_commitment_bytes: [u8; 32] = vote_commitment.into();
168
169 SimpleCertificate {
170 data,
171 vote_commitment: Commitment::from_raw(vote_commitment_bytes),
172 view_number: view,
173 signatures: Some(sig),
174 _pd: PhantomData,
175 }
176 }
177 async fn is_valid_cert(
178 &self,
179 stake_table: &[<TYPES::SignatureKey as SignatureKey>::StakeTableEntry],
180 threshold: U256,
181 upgrade_lock: &UpgradeLock<TYPES>,
182 ) -> Result<()> {
183 if self.view_number == ViewNumber::genesis() {
184 return Ok(());
185 }
186 let real_qc_pp =
187 <TYPES::SignatureKey as SignatureKey>::public_parameter(stake_table, threshold);
188 let commit = self.data_commitment(upgrade_lock).await?;
189
190 let Some(ref signatures) = self.signatures else {
191 bail!("No signatures found while validating certificate");
192 };
193
194 <TYPES::SignatureKey as SignatureKey>::check(&real_qc_pp, commit.as_ref(), signatures)
195 .wrap()
196 .context(|e| warn!("Signature check failed: {e}"))
197 }
198 fn signers(
199 &self,
200 stake_table: &[<TYPES::SignatureKey as SignatureKey>::StakeTableEntry],
201 threshold: U256,
202 ) -> Result<Vec<<TYPES::SignatureKey as SignatureKey>::VerificationKeyType>> {
203 self.signers(stake_table, threshold)
204 }
205 async fn stake_table_entry(
207 membership: &EpochMembership<TYPES>,
208 pub_key: &TYPES::SignatureKey,
209 ) -> Option<PeerConfig<TYPES>> {
210 membership.da_stake(pub_key).await
211 }
212
213 async fn stake_table(membership: &EpochMembership<TYPES>) -> HSStakeTable<TYPES> {
215 membership.da_stake_table().await
216 }
217 async fn total_nodes(membership: &EpochMembership<TYPES>) -> usize {
219 membership.da_total_nodes().await
220 }
221 async fn threshold(membership: &EpochMembership<TYPES>) -> U256 {
222 membership.da_success_threshold().await
223 }
224 fn data(&self) -> &Self::Voteable {
225 &self.data
226 }
227 async fn data_commitment(
228 &self,
229 upgrade_lock: &UpgradeLock<TYPES>,
230 ) -> Result<Commitment<VersionedVoteData<TYPES, DaData>>> {
231 Ok(
232 VersionedVoteData::new(self.data.clone(), self.view_number, upgrade_lock)
233 .await?
234 .commit(),
235 )
236 }
237}
238
239impl<TYPES: NodeType, THRESHOLD: Threshold<TYPES>> Certificate<TYPES, DaData2>
240 for SimpleCertificate<TYPES, DaData2, THRESHOLD>
241{
242 type Voteable = DaData2;
243 type Threshold = THRESHOLD;
244
245 fn create_signed_certificate(
246 vote_commitment: Commitment<VersionedVoteData<TYPES, DaData2>>,
247 data: Self::Voteable,
248 sig: <TYPES::SignatureKey as SignatureKey>::QcType,
249 view: ViewNumber,
250 ) -> Self {
251 let vote_commitment_bytes: [u8; 32] = vote_commitment.into();
252
253 SimpleCertificate {
254 data,
255 vote_commitment: Commitment::from_raw(vote_commitment_bytes),
256 view_number: view,
257 signatures: Some(sig),
258 _pd: PhantomData,
259 }
260 }
261 async fn is_valid_cert(
262 &self,
263 stake_table: &[<TYPES::SignatureKey as SignatureKey>::StakeTableEntry],
264 threshold: U256,
265 upgrade_lock: &UpgradeLock<TYPES>,
266 ) -> Result<()> {
267 if self.view_number == ViewNumber::genesis() {
268 return Ok(());
269 }
270 let real_qc_pp =
271 <TYPES::SignatureKey as SignatureKey>::public_parameter(stake_table, threshold);
272 let commit = self.data_commitment(upgrade_lock).await?;
273
274 <TYPES::SignatureKey as SignatureKey>::check(
275 &real_qc_pp,
276 commit.as_ref(),
277 self.signatures.as_ref().unwrap(),
278 )
279 .wrap()
280 .context(|e| warn!("Signature check failed: {e}"))
281 }
282 fn signers(
283 &self,
284 stake_table: &[<TYPES::SignatureKey as SignatureKey>::StakeTableEntry],
285 threshold: U256,
286 ) -> Result<Vec<<TYPES::SignatureKey as SignatureKey>::VerificationKeyType>> {
287 self.signers(stake_table, threshold)
288 }
289 async fn stake_table_entry(
291 membership: &EpochMembership<TYPES>,
292 pub_key: &TYPES::SignatureKey,
293 ) -> Option<PeerConfig<TYPES>> {
294 membership.da_stake(pub_key).await
295 }
296
297 async fn stake_table(membership: &EpochMembership<TYPES>) -> HSStakeTable<TYPES> {
299 membership.da_stake_table().await
300 }
301 async fn total_nodes(membership: &EpochMembership<TYPES>) -> usize {
303 membership.da_total_nodes().await
304 }
305 async fn threshold(membership: &EpochMembership<TYPES>) -> U256 {
306 membership.da_success_threshold().await
307 }
308 fn data(&self) -> &Self::Voteable {
309 &self.data
310 }
311 async fn data_commitment(
312 &self,
313 upgrade_lock: &UpgradeLock<TYPES>,
314 ) -> Result<Commitment<VersionedVoteData<TYPES, DaData2>>> {
315 Ok(
316 VersionedVoteData::new(self.data.clone(), self.view_number, upgrade_lock)
317 .await?
318 .commit(),
319 )
320 }
321}
322
323impl<
324 TYPES: NodeType,
325 VOTEABLE: Voteable<TYPES> + 'static + QuorumMarker,
326 THRESHOLD: Threshold<TYPES>,
327> Certificate<TYPES, VOTEABLE> for SimpleCertificate<TYPES, VOTEABLE, THRESHOLD>
328{
329 type Voteable = VOTEABLE;
330 type Threshold = THRESHOLD;
331
332 fn create_signed_certificate(
333 vote_commitment: Commitment<VersionedVoteData<TYPES, VOTEABLE>>,
334 data: Self::Voteable,
335 sig: <TYPES::SignatureKey as SignatureKey>::QcType,
336 view: ViewNumber,
337 ) -> Self {
338 let vote_commitment_bytes: [u8; 32] = vote_commitment.into();
339
340 SimpleCertificate {
341 data,
342 vote_commitment: Commitment::from_raw(vote_commitment_bytes),
343 view_number: view,
344 signatures: Some(sig),
345 _pd: PhantomData,
346 }
347 }
348 async fn is_valid_cert(
349 &self,
350 stake_table: &[<TYPES::SignatureKey as SignatureKey>::StakeTableEntry],
351 threshold: U256,
352 upgrade_lock: &UpgradeLock<TYPES>,
353 ) -> Result<()> {
354 if self.view_number == ViewNumber::genesis() {
355 return Ok(());
356 }
357 let real_qc_pp =
358 <TYPES::SignatureKey as SignatureKey>::public_parameter(stake_table, threshold);
359 let commit = self.data_commitment(upgrade_lock).await?;
360
361 <TYPES::SignatureKey as SignatureKey>::check(
362 &real_qc_pp,
363 commit.as_ref(),
364 self.signatures.as_ref().unwrap(),
365 )
366 .wrap()
367 .context(|e| warn!("Signature check failed: {e}"))
368 }
369 fn signers(
370 &self,
371 stake_table: &[<TYPES::SignatureKey as SignatureKey>::StakeTableEntry],
372 threshold: U256,
373 ) -> Result<Vec<<TYPES::SignatureKey as SignatureKey>::VerificationKeyType>> {
374 self.signers(stake_table, threshold)
375 }
376 async fn threshold(membership: &EpochMembership<TYPES>) -> U256 {
377 THRESHOLD::threshold(membership).await
378 }
379
380 async fn stake_table_entry(
381 membership: &EpochMembership<TYPES>,
382 pub_key: &TYPES::SignatureKey,
383 ) -> Option<PeerConfig<TYPES>> {
384 membership.stake(pub_key).await
385 }
386
387 async fn stake_table(membership: &EpochMembership<TYPES>) -> HSStakeTable<TYPES> {
388 membership.stake_table().await
389 }
390
391 async fn total_nodes(membership: &EpochMembership<TYPES>) -> usize {
393 membership.total_nodes().await
394 }
395
396 fn data(&self) -> &Self::Voteable {
397 &self.data
398 }
399 async fn data_commitment(
400 &self,
401 upgrade_lock: &UpgradeLock<TYPES>,
402 ) -> Result<Commitment<VersionedVoteData<TYPES, VOTEABLE>>> {
403 Ok(
404 VersionedVoteData::new(self.data.clone(), self.view_number, upgrade_lock)
405 .await?
406 .commit(),
407 )
408 }
409}
410
411impl<TYPES: NodeType, VOTEABLE: Voteable<TYPES> + 'static, THRESHOLD: Threshold<TYPES>>
412 HasViewNumber for SimpleCertificate<TYPES, VOTEABLE, THRESHOLD>
413{
414 fn view_number(&self) -> ViewNumber {
415 self.view_number
416 }
417}
418
419impl<TYPES: NodeType, VOTEABLE: Voteable<TYPES> + HasEpoch + 'static, THRESHOLD: Threshold<TYPES>>
420 HasEpoch for SimpleCertificate<TYPES, VOTEABLE, THRESHOLD>
421{
422 fn epoch(&self) -> Option<EpochNumber> {
423 self.data.epoch()
424 }
425}
426
427impl<TYPES: NodeType> Display for QuorumCertificate<TYPES> {
428 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
429 write!(f, "view: {:?}", self.view_number)
430 }
431}
432
433impl<TYPES: NodeType> UpgradeCertificate<TYPES> {
434 pub async fn is_relevant(&self, view_number: ViewNumber) -> Result<()> {
440 ensure!(
441 self.data.new_version_first_view >= view_number,
442 "Upgrade certificate is no longer relevant."
443 );
444
445 Ok(())
446 }
447
448 pub async fn validate(
452 upgrade_certificate: &Option<Self>,
453 membership: &EpochMembership<TYPES>,
454 epoch: Option<EpochNumber>,
455 upgrade_lock: &UpgradeLock<TYPES>,
456 ) -> Result<()> {
457 ensure!(epoch == membership.epoch(), "Epochs don't match!");
458 if let Some(cert) = upgrade_certificate {
459 let membership_stake_table = membership.stake_table().await;
460 let membership_upgrade_threshold = membership.upgrade_threshold().await;
461
462 cert.is_valid_cert(
463 &StakeTableEntries::<TYPES>::from(membership_stake_table).0,
464 membership_upgrade_threshold,
465 upgrade_lock,
466 )
467 .await
468 .context(|e| warn!("Invalid upgrade certificate: {e}"))?;
469 }
470
471 Ok(())
472 }
473
474 pub fn upgrading_in(&self, view: ViewNumber) -> bool {
477 view > self.data.old_version_last_view && view < self.data.new_version_first_view
478 }
479}
480
481impl<TYPES: NodeType> QuorumCertificate<TYPES> {
482 pub fn to_qc2(self) -> QuorumCertificate2<TYPES> {
484 let bytes: [u8; 32] = self.data.leaf_commit.into();
485 let data = QuorumData2 {
486 leaf_commit: Commitment::from_raw(bytes),
487 epoch: None,
488 block_number: None,
489 };
490
491 let bytes: [u8; 32] = self.vote_commitment.into();
492 let vote_commitment = Commitment::from_raw(bytes);
493
494 SimpleCertificate {
495 data,
496 vote_commitment,
497 view_number: self.view_number,
498 signatures: self.signatures.clone(),
499 _pd: PhantomData,
500 }
501 }
502}
503
504impl<TYPES: NodeType> QuorumCertificate2<TYPES> {
505 pub fn to_qc(self) -> QuorumCertificate<TYPES> {
507 let bytes: [u8; 32] = self.data.leaf_commit.into();
508 let data = QuorumData {
509 leaf_commit: Commitment::from_raw(bytes),
510 };
511
512 let bytes: [u8; 32] = self.vote_commitment.into();
513 let vote_commitment = Commitment::from_raw(bytes);
514
515 SimpleCertificate {
516 data,
517 vote_commitment,
518 view_number: self.view_number,
519 signatures: self.signatures.clone(),
520 _pd: PhantomData,
521 }
522 }
523}
524
525impl<TYPES: NodeType> DaCertificate<TYPES> {
526 pub fn to_dac2(self) -> DaCertificate2<TYPES> {
528 let data = DaData2 {
529 payload_commit: self.data.payload_commit,
530 next_epoch_payload_commit: None,
531 epoch: None,
532 };
533
534 let bytes: [u8; 32] = self.vote_commitment.into();
535 let vote_commitment = Commitment::from_raw(bytes);
536
537 SimpleCertificate {
538 data,
539 vote_commitment,
540 view_number: self.view_number,
541 signatures: self.signatures.clone(),
542 _pd: PhantomData,
543 }
544 }
545}
546
547impl<TYPES: NodeType> DaCertificate2<TYPES> {
548 pub fn to_dac(self) -> DaCertificate<TYPES> {
550 let data = DaData {
551 payload_commit: self.data.payload_commit,
552 };
553
554 let bytes: [u8; 32] = self.vote_commitment.into();
555 let vote_commitment = Commitment::from_raw(bytes);
556
557 SimpleCertificate {
558 data,
559 vote_commitment,
560 view_number: self.view_number,
561 signatures: self.signatures.clone(),
562 _pd: PhantomData,
563 }
564 }
565}
566
567impl<TYPES: NodeType> ViewSyncPreCommitCertificate<TYPES> {
568 pub fn to_vsc2(self) -> ViewSyncPreCommitCertificate2<TYPES> {
570 let data = ViewSyncPreCommitData2 {
571 relay: self.data.relay,
572 round: self.data.round,
573 epoch: None,
574 };
575
576 let bytes: [u8; 32] = self.vote_commitment.into();
577 let vote_commitment = Commitment::from_raw(bytes);
578
579 SimpleCertificate {
580 data,
581 vote_commitment,
582 view_number: self.view_number,
583 signatures: self.signatures.clone(),
584 _pd: PhantomData,
585 }
586 }
587}
588
589impl<TYPES: NodeType> ViewSyncPreCommitCertificate2<TYPES> {
590 pub fn to_vsc(self) -> ViewSyncPreCommitCertificate<TYPES> {
592 let data = ViewSyncPreCommitData {
593 relay: self.data.relay,
594 round: self.data.round,
595 };
596
597 let bytes: [u8; 32] = self.vote_commitment.into();
598 let vote_commitment = Commitment::from_raw(bytes);
599
600 SimpleCertificate {
601 data,
602 vote_commitment,
603 view_number: self.view_number,
604 signatures: self.signatures.clone(),
605 _pd: PhantomData,
606 }
607 }
608}
609
610impl<TYPES: NodeType> ViewSyncCommitCertificate<TYPES> {
611 pub fn to_vsc2(self) -> ViewSyncCommitCertificate2<TYPES> {
613 let data = ViewSyncCommitData2 {
614 relay: self.data.relay,
615 round: self.data.round,
616 epoch: None,
617 };
618
619 let bytes: [u8; 32] = self.vote_commitment.into();
620 let vote_commitment = Commitment::from_raw(bytes);
621
622 SimpleCertificate {
623 data,
624 vote_commitment,
625 view_number: self.view_number,
626 signatures: self.signatures.clone(),
627 _pd: PhantomData,
628 }
629 }
630}
631
632impl<TYPES: NodeType> ViewSyncCommitCertificate2<TYPES> {
633 pub fn to_vsc(self) -> ViewSyncCommitCertificate<TYPES> {
635 let data = ViewSyncCommitData {
636 relay: self.data.relay,
637 round: self.data.round,
638 };
639
640 let bytes: [u8; 32] = self.vote_commitment.into();
641 let vote_commitment = Commitment::from_raw(bytes);
642
643 SimpleCertificate {
644 data,
645 vote_commitment,
646 view_number: self.view_number,
647 signatures: self.signatures.clone(),
648 _pd: PhantomData,
649 }
650 }
651}
652
653impl<TYPES: NodeType> ViewSyncFinalizeCertificate<TYPES> {
654 pub fn to_vsc2(self) -> ViewSyncFinalizeCertificate2<TYPES> {
656 let data = ViewSyncFinalizeData2 {
657 relay: self.data.relay,
658 round: self.data.round,
659 epoch: None,
660 };
661
662 let bytes: [u8; 32] = self.vote_commitment.into();
663 let vote_commitment = Commitment::from_raw(bytes);
664
665 SimpleCertificate {
666 data,
667 vote_commitment,
668 view_number: self.view_number,
669 signatures: self.signatures.clone(),
670 _pd: PhantomData,
671 }
672 }
673}
674
675impl<TYPES: NodeType> ViewSyncFinalizeCertificate2<TYPES> {
676 pub fn to_vsc(self) -> ViewSyncFinalizeCertificate<TYPES> {
678 let data = ViewSyncFinalizeData {
679 relay: self.data.relay,
680 round: self.data.round,
681 };
682
683 let bytes: [u8; 32] = self.vote_commitment.into();
684 let vote_commitment = Commitment::from_raw(bytes);
685
686 SimpleCertificate {
687 data,
688 vote_commitment,
689 view_number: self.view_number,
690 signatures: self.signatures.clone(),
691 _pd: PhantomData,
692 }
693 }
694}
695
696impl<TYPES: NodeType> TimeoutCertificate<TYPES> {
697 pub fn to_tc2(self) -> TimeoutCertificate2<TYPES> {
699 let data = TimeoutData2 {
700 view: self.data.view,
701 epoch: None,
702 };
703
704 let bytes: [u8; 32] = self.vote_commitment.into();
705 let vote_commitment = Commitment::from_raw(bytes);
706
707 SimpleCertificate {
708 data,
709 vote_commitment,
710 view_number: self.view_number,
711 signatures: self.signatures.clone(),
712 _pd: PhantomData,
713 }
714 }
715}
716
717impl<TYPES: NodeType> TimeoutCertificate2<TYPES> {
718 pub fn to_tc(self) -> TimeoutCertificate<TYPES> {
720 let data = TimeoutData {
721 view: self.data.view,
722 };
723
724 let bytes: [u8; 32] = self.vote_commitment.into();
725 let vote_commitment = Commitment::from_raw(bytes);
726
727 SimpleCertificate {
728 data,
729 vote_commitment,
730 view_number: self.view_number,
731 signatures: self.signatures.clone(),
732 _pd: PhantomData,
733 }
734 }
735}
736
737pub type QuorumCertificate<TYPES> = SimpleCertificate<TYPES, QuorumData<TYPES>, SuccessThreshold>;
739pub type QuorumCertificate2<TYPES> = SimpleCertificate<TYPES, QuorumData2<TYPES>, SuccessThreshold>;
741pub type NextEpochQuorumCertificate2<TYPES> =
743 SimpleCertificate<TYPES, NextEpochQuorumData2<TYPES>, SuccessThreshold>;
744pub type DaCertificate<TYPES> = SimpleCertificate<TYPES, DaData, SuccessThreshold>;
746pub type DaCertificate2<TYPES> = SimpleCertificate<TYPES, DaData2, SuccessThreshold>;
748pub type TimeoutCertificate<TYPES> = SimpleCertificate<TYPES, TimeoutData, SuccessThreshold>;
750pub type TimeoutCertificate2<TYPES> = SimpleCertificate<TYPES, TimeoutData2, SuccessThreshold>;
752pub type ViewSyncPreCommitCertificate<TYPES> =
754 SimpleCertificate<TYPES, ViewSyncPreCommitData, OneHonestThreshold>;
755pub type ViewSyncPreCommitCertificate2<TYPES> =
757 SimpleCertificate<TYPES, ViewSyncPreCommitData2, OneHonestThreshold>;
758pub type ViewSyncCommitCertificate<TYPES> =
760 SimpleCertificate<TYPES, ViewSyncCommitData, SuccessThreshold>;
761pub type ViewSyncCommitCertificate2<TYPES> =
763 SimpleCertificate<TYPES, ViewSyncCommitData2, SuccessThreshold>;
764pub type ViewSyncFinalizeCertificate<TYPES> =
766 SimpleCertificate<TYPES, ViewSyncFinalizeData, SuccessThreshold>;
767pub type ViewSyncFinalizeCertificate2<TYPES> =
769 SimpleCertificate<TYPES, ViewSyncFinalizeData2, SuccessThreshold>;
770pub type UpgradeCertificate<TYPES> =
772 SimpleCertificate<TYPES, UpgradeProposalData, UpgradeThreshold>;
773
774#[derive(Serialize, Deserialize, Eq, Hash, PartialEq, Debug, Clone)]
776pub struct LightClientStateUpdateCertificateV2<TYPES: NodeType> {
777 pub epoch: EpochNumber,
779 pub light_client_state: LightClientState,
781 pub next_stake_table_state: StakeTableState,
783 #[allow(clippy::type_complexity)]
785 pub signatures: Vec<(
786 TYPES::StateSignatureKey,
787 <TYPES::StateSignatureKey as StateSignatureKey>::StateSignature, <TYPES::StateSignatureKey as StateSignatureKey>::StateSignature, )>,
790 pub auth_root: FixedBytes<32>,
795}
796
797#[derive(Serialize, Deserialize, Eq, Hash, PartialEq, Debug, Clone)]
799pub struct LightClientStateUpdateCertificateV1<TYPES: NodeType> {
800 pub epoch: EpochNumber,
802 pub light_client_state: LightClientState,
804 pub next_stake_table_state: StakeTableState,
806 pub signatures: Vec<(
808 TYPES::StateSignatureKey,
809 <TYPES::StateSignatureKey as StateSignatureKey>::StateSignature,
810 )>,
811}
812
813impl<TYPES: NodeType> From<LightClientStateUpdateCertificateV1<TYPES>>
814 for LightClientStateUpdateCertificateV2<TYPES>
815{
816 fn from(v1: LightClientStateUpdateCertificateV1<TYPES>) -> Self {
817 Self {
818 epoch: v1.epoch,
819 light_client_state: v1.light_client_state,
820 next_stake_table_state: v1.next_stake_table_state,
821 signatures: v1
822 .signatures
823 .into_iter()
824 .map(|(key, sig)| (key, sig.clone(), sig)) .collect(),
826 auth_root: Default::default(),
827 }
828 }
829}
830
831impl<TYPES: NodeType> From<LightClientStateUpdateCertificateV2<TYPES>>
832 for LightClientStateUpdateCertificateV1<TYPES>
833{
834 fn from(v2: LightClientStateUpdateCertificateV2<TYPES>) -> Self {
835 Self {
836 epoch: v2.epoch,
837 light_client_state: v2.light_client_state,
838 next_stake_table_state: v2.next_stake_table_state,
839 signatures: v2
840 .signatures
841 .into_iter()
842 .map(|(key, _, sig)| (key, sig))
843 .collect(),
844 }
845 }
846}
847
848impl<TYPES: NodeType> HasViewNumber for LightClientStateUpdateCertificateV2<TYPES> {
849 fn view_number(&self) -> ViewNumber {
850 ViewNumber::new(self.light_client_state.view_number)
851 }
852}
853
854impl<TYPES: NodeType> HasEpoch for LightClientStateUpdateCertificateV2<TYPES> {
855 fn epoch(&self) -> Option<EpochNumber> {
856 Some(self.epoch)
857 }
858}
859
860impl<TYPES: NodeType> LightClientStateUpdateCertificateV1<TYPES> {
861 pub fn genesis() -> Self {
862 Self {
863 epoch: EpochNumber::genesis(),
864 light_client_state: Default::default(),
865 next_stake_table_state: Default::default(),
866 signatures: vec![],
867 }
868 }
869}
870
871impl<TYPES: NodeType> LightClientStateUpdateCertificateV2<TYPES> {
872 pub fn genesis() -> Self {
873 Self {
874 epoch: EpochNumber::genesis(),
875 light_client_state: Default::default(),
876 next_stake_table_state: Default::default(),
877 signatures: vec![],
878 auth_root: Default::default(),
879 }
880 }
881}
882
883#[derive(Serialize, Deserialize, Eq, Hash, PartialEq, Debug, Clone)]
884#[serde(bound(deserialize = "QuorumCertificate2<TYPES>:for<'a> Deserialize<'a>"))]
885pub struct EpochRootQuorumCertificateV2<TYPES: NodeType> {
886 pub qc: QuorumCertificate2<TYPES>,
887 pub state_cert: LightClientStateUpdateCertificateV2<TYPES>,
888}
889
890impl<TYPES: NodeType> HasViewNumber for EpochRootQuorumCertificateV2<TYPES> {
891 fn view_number(&self) -> ViewNumber {
892 self.qc.view_number()
893 }
894}
895
896impl<TYPES: NodeType> HasEpoch for EpochRootQuorumCertificateV2<TYPES> {
897 fn epoch(&self) -> Option<EpochNumber> {
898 self.qc.epoch()
899 }
900}
901
902#[derive(Serialize, Deserialize, Eq, Hash, PartialEq, Debug, Clone)]
903#[serde(bound(deserialize = "QuorumCertificate2<TYPES>:for<'a> Deserialize<'a>"))]
904pub struct EpochRootQuorumCertificateV1<TYPES: NodeType> {
905 pub qc: QuorumCertificate2<TYPES>,
906 pub state_cert: LightClientStateUpdateCertificateV1<TYPES>,
907}
908
909impl<TYPES: NodeType> HasViewNumber for EpochRootQuorumCertificateV1<TYPES> {
910 fn view_number(&self) -> ViewNumber {
911 self.qc.view_number()
912 }
913}
914
915impl<TYPES: NodeType> HasEpoch for EpochRootQuorumCertificateV1<TYPES> {
916 fn epoch(&self) -> Option<EpochNumber> {
917 self.qc.epoch()
918 }
919}
920
921impl<TYPES: NodeType> From<EpochRootQuorumCertificateV1<TYPES>>
922 for EpochRootQuorumCertificateV2<TYPES>
923{
924 fn from(root_qc: EpochRootQuorumCertificateV1<TYPES>) -> Self {
925 Self {
926 qc: root_qc.qc,
927 state_cert: root_qc.state_cert.into(),
928 }
929 }
930}
931
932impl<TYPES: NodeType> From<EpochRootQuorumCertificateV2<TYPES>>
933 for EpochRootQuorumCertificateV1<TYPES>
934{
935 fn from(root_qc: EpochRootQuorumCertificateV2<TYPES>) -> Self {
936 Self {
937 qc: root_qc.qc,
938 state_cert: root_qc.state_cert.into(),
939 }
940 }
941}
942
943#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
949#[serde(bound = "")]
950pub struct CertificatePair<TYPES: NodeType> {
951 qc: QuorumCertificate2<TYPES>,
953
954 next_epoch_qc: Option<NextEpochQuorumCertificate2<TYPES>>,
956}
957
958impl<TYPES: NodeType> CertificatePair<TYPES> {
959 pub fn new(
961 qc: QuorumCertificate2<TYPES>,
962 next_epoch_qc: Option<NextEpochQuorumCertificate2<TYPES>>,
963 ) -> Self {
964 Self { qc, next_epoch_qc }
965 }
966
967 pub fn non_epoch_change(qc: QuorumCertificate2<TYPES>) -> Self {
969 Self::new(qc, None)
970 }
971
972 pub fn for_parent(leaf: &Leaf2<TYPES>) -> Self {
974 Self {
975 qc: leaf.justify_qc(),
976 next_epoch_qc: leaf.next_epoch_justify_qc(),
977 }
978 }
979
980 pub fn qc(&self) -> &QuorumCertificate2<TYPES> {
982 &self.qc
983 }
984
985 pub fn next_epoch_qc(&self) -> Option<&NextEpochQuorumCertificate2<TYPES>> {
987 self.next_epoch_qc.as_ref()
988 }
989
990 pub fn leaf_commit(&self) -> Commitment<Leaf2<TYPES>> {
992 self.qc.data.leaf_commit
993 }
994
995 pub fn epoch(&self) -> Option<EpochNumber> {
999 self.qc.data.epoch
1000 }
1001
1002 pub fn block_number(&self) -> Option<u64> {
1006 self.qc.data.block_number
1007 }
1008
1009 pub fn verify_next_epoch_qc(
1019 &self,
1020 epoch_height: u64,
1021 ) -> Result<Option<&NextEpochQuorumCertificate2<TYPES>>> {
1022 let block_number = self.qc.data.block_number.context(warn!(
1023 "QC for epoch {:?} has no block number",
1024 self.qc.data.epoch
1025 ))?;
1026 if !is_epoch_transition(block_number, epoch_height) {
1027 tracing::debug!(
1028 block_number,
1029 epoch_height,
1030 "QC is not in an epoch transition"
1031 );
1032 return Ok(None);
1033 }
1034
1035 let next_epoch_qc = self.next_epoch_qc.as_ref().context(warn!(
1036 "Received High QC for the transition block {block_number} but not the next epoch QC"
1037 ))?;
1038
1039 ensure!(self.qc.view_number == next_epoch_qc.view_number);
1041 ensure!(self.qc.data == *next_epoch_qc.data);
1042
1043 Ok(Some(next_epoch_qc))
1044 }
1045}
1046
1047impl<TYPES: NodeType> HasViewNumber for CertificatePair<TYPES> {
1048 fn view_number(&self) -> ViewNumber {
1049 self.qc.view_number()
1050 }
1051}