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 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)?;
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 fn data_commitment(
228 &self,
229 upgrade_lock: &UpgradeLock<TYPES>,
230 ) -> Result<Commitment<VersionedVoteData<TYPES, DaData>>> {
231 Ok(VersionedVoteData::new(self.data.clone(), self.view_number, upgrade_lock)?.commit())
232 }
233}
234
235impl<TYPES: NodeType, THRESHOLD: Threshold<TYPES>> Certificate<TYPES, DaData2>
236 for SimpleCertificate<TYPES, DaData2, THRESHOLD>
237{
238 type Voteable = DaData2;
239 type Threshold = THRESHOLD;
240
241 fn create_signed_certificate(
242 vote_commitment: Commitment<VersionedVoteData<TYPES, DaData2>>,
243 data: Self::Voteable,
244 sig: <TYPES::SignatureKey as SignatureKey>::QcType,
245 view: ViewNumber,
246 ) -> Self {
247 let vote_commitment_bytes: [u8; 32] = vote_commitment.into();
248
249 SimpleCertificate {
250 data,
251 vote_commitment: Commitment::from_raw(vote_commitment_bytes),
252 view_number: view,
253 signatures: Some(sig),
254 _pd: PhantomData,
255 }
256 }
257 fn is_valid_cert(
258 &self,
259 stake_table: &[<TYPES::SignatureKey as SignatureKey>::StakeTableEntry],
260 threshold: U256,
261 upgrade_lock: &UpgradeLock<TYPES>,
262 ) -> Result<()> {
263 if self.view_number == ViewNumber::genesis() {
264 return Ok(());
265 }
266 let real_qc_pp =
267 <TYPES::SignatureKey as SignatureKey>::public_parameter(stake_table, threshold);
268 let commit = self.data_commitment(upgrade_lock)?;
269 let signatures = self
270 .signatures
271 .as_ref()
272 .ok_or_else(|| warn!("missing signatures"))?;
273
274 <TYPES::SignatureKey as SignatureKey>::check(&real_qc_pp, commit.as_ref(), signatures)
275 .wrap()
276 .context(|e| warn!("Signature check failed: {e}"))
277 }
278 fn signers(
279 &self,
280 stake_table: &[<TYPES::SignatureKey as SignatureKey>::StakeTableEntry],
281 threshold: U256,
282 ) -> Result<Vec<<TYPES::SignatureKey as SignatureKey>::VerificationKeyType>> {
283 self.signers(stake_table, threshold)
284 }
285 async fn stake_table_entry(
287 membership: &EpochMembership<TYPES>,
288 pub_key: &TYPES::SignatureKey,
289 ) -> Option<PeerConfig<TYPES>> {
290 membership.da_stake(pub_key).await
291 }
292
293 async fn stake_table(membership: &EpochMembership<TYPES>) -> HSStakeTable<TYPES> {
295 membership.da_stake_table().await
296 }
297 async fn total_nodes(membership: &EpochMembership<TYPES>) -> usize {
299 membership.da_total_nodes().await
300 }
301 async fn threshold(membership: &EpochMembership<TYPES>) -> U256 {
302 membership.da_success_threshold().await
303 }
304 fn data(&self) -> &Self::Voteable {
305 &self.data
306 }
307 fn data_commitment(
308 &self,
309 upgrade_lock: &UpgradeLock<TYPES>,
310 ) -> Result<Commitment<VersionedVoteData<TYPES, DaData2>>> {
311 Ok(VersionedVoteData::new(self.data.clone(), self.view_number, upgrade_lock)?.commit())
312 }
313}
314
315impl<
316 TYPES: NodeType,
317 VOTEABLE: Voteable<TYPES> + 'static + QuorumMarker,
318 THRESHOLD: Threshold<TYPES>,
319> Certificate<TYPES, VOTEABLE> for SimpleCertificate<TYPES, VOTEABLE, THRESHOLD>
320{
321 type Voteable = VOTEABLE;
322 type Threshold = THRESHOLD;
323
324 fn create_signed_certificate(
325 vote_commitment: Commitment<VersionedVoteData<TYPES, VOTEABLE>>,
326 data: Self::Voteable,
327 sig: <TYPES::SignatureKey as SignatureKey>::QcType,
328 view: ViewNumber,
329 ) -> Self {
330 let vote_commitment_bytes: [u8; 32] = vote_commitment.into();
331
332 SimpleCertificate {
333 data,
334 vote_commitment: Commitment::from_raw(vote_commitment_bytes),
335 view_number: view,
336 signatures: Some(sig),
337 _pd: PhantomData,
338 }
339 }
340 fn is_valid_cert(
341 &self,
342 stake_table: &[<TYPES::SignatureKey as SignatureKey>::StakeTableEntry],
343 threshold: U256,
344 upgrade_lock: &UpgradeLock<TYPES>,
345 ) -> Result<()> {
346 if self.view_number == ViewNumber::genesis() {
347 return Ok(());
348 }
349 let real_qc_pp =
350 <TYPES::SignatureKey as SignatureKey>::public_parameter(stake_table, threshold);
351 let commit = self.data_commitment(upgrade_lock)?;
352 let signatures = self
353 .signatures
354 .as_ref()
355 .ok_or_else(|| warn!("missing signatures"))?;
356
357 <TYPES::SignatureKey as SignatureKey>::check(&real_qc_pp, commit.as_ref(), signatures)
358 .wrap()
359 .context(|e| warn!("Signature check failed: {e}"))
360 }
361 fn signers(
362 &self,
363 stake_table: &[<TYPES::SignatureKey as SignatureKey>::StakeTableEntry],
364 threshold: U256,
365 ) -> Result<Vec<<TYPES::SignatureKey as SignatureKey>::VerificationKeyType>> {
366 self.signers(stake_table, threshold)
367 }
368 async fn threshold(membership: &EpochMembership<TYPES>) -> U256 {
369 THRESHOLD::threshold(membership).await
370 }
371
372 async fn stake_table_entry(
373 membership: &EpochMembership<TYPES>,
374 pub_key: &TYPES::SignatureKey,
375 ) -> Option<PeerConfig<TYPES>> {
376 membership.stake(pub_key).await
377 }
378
379 async fn stake_table(membership: &EpochMembership<TYPES>) -> HSStakeTable<TYPES> {
380 membership.stake_table().await
381 }
382
383 async fn total_nodes(membership: &EpochMembership<TYPES>) -> usize {
385 membership.total_nodes().await
386 }
387
388 fn data(&self) -> &Self::Voteable {
389 &self.data
390 }
391 fn data_commitment(
392 &self,
393 upgrade_lock: &UpgradeLock<TYPES>,
394 ) -> Result<Commitment<VersionedVoteData<TYPES, VOTEABLE>>> {
395 Ok(VersionedVoteData::new(self.data.clone(), self.view_number, upgrade_lock)?.commit())
396 }
397}
398
399impl<TYPES: NodeType, VOTEABLE: Voteable<TYPES> + 'static, THRESHOLD: Threshold<TYPES>>
400 HasViewNumber for SimpleCertificate<TYPES, VOTEABLE, THRESHOLD>
401{
402 fn view_number(&self) -> ViewNumber {
403 self.view_number
404 }
405}
406
407impl<TYPES: NodeType, VOTEABLE: Voteable<TYPES> + HasEpoch + 'static, THRESHOLD: Threshold<TYPES>>
408 HasEpoch for SimpleCertificate<TYPES, VOTEABLE, THRESHOLD>
409{
410 fn epoch(&self) -> Option<EpochNumber> {
411 self.data.epoch()
412 }
413}
414
415impl<TYPES: NodeType> Display for QuorumCertificate<TYPES> {
416 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
417 write!(f, "view: {:?}", self.view_number)
418 }
419}
420
421impl<TYPES: NodeType> UpgradeCertificate<TYPES> {
422 pub async fn is_relevant(&self, view_number: ViewNumber) -> Result<()> {
428 ensure!(
429 self.data.new_version_first_view >= view_number,
430 "Upgrade certificate is no longer relevant."
431 );
432
433 Ok(())
434 }
435
436 pub async fn validate(
440 upgrade_certificate: &Option<Self>,
441 membership: &EpochMembership<TYPES>,
442 epoch: Option<EpochNumber>,
443 upgrade_lock: &UpgradeLock<TYPES>,
444 ) -> Result<()> {
445 ensure!(epoch == membership.epoch(), "Epochs don't match!");
446 if let Some(cert) = upgrade_certificate {
447 let membership_stake_table = membership.stake_table().await;
448 let membership_upgrade_threshold = membership.upgrade_threshold().await;
449
450 cert.is_valid_cert(
451 &StakeTableEntries::<TYPES>::from(membership_stake_table).0,
452 membership_upgrade_threshold,
453 upgrade_lock,
454 )
455 .context(|e| warn!("Invalid upgrade certificate: {e}"))?;
456 }
457
458 Ok(())
459 }
460
461 pub fn upgrading_in(&self, view: ViewNumber) -> bool {
464 view > self.data.old_version_last_view && view < self.data.new_version_first_view
465 }
466}
467
468impl<TYPES: NodeType> QuorumCertificate<TYPES> {
469 pub fn to_qc2(self) -> QuorumCertificate2<TYPES> {
471 let bytes: [u8; 32] = self.data.leaf_commit.into();
472 let data = QuorumData2 {
473 leaf_commit: Commitment::from_raw(bytes),
474 epoch: None,
475 block_number: None,
476 };
477
478 let bytes: [u8; 32] = self.vote_commitment.into();
479 let vote_commitment = Commitment::from_raw(bytes);
480
481 SimpleCertificate {
482 data,
483 vote_commitment,
484 view_number: self.view_number,
485 signatures: self.signatures.clone(),
486 _pd: PhantomData,
487 }
488 }
489}
490
491impl<TYPES: NodeType> QuorumCertificate2<TYPES> {
492 pub fn to_qc(self) -> QuorumCertificate<TYPES> {
494 let bytes: [u8; 32] = self.data.leaf_commit.into();
495 let data = QuorumData {
496 leaf_commit: Commitment::from_raw(bytes),
497 };
498
499 let bytes: [u8; 32] = self.vote_commitment.into();
500 let vote_commitment = Commitment::from_raw(bytes);
501
502 SimpleCertificate {
503 data,
504 vote_commitment,
505 view_number: self.view_number,
506 signatures: self.signatures.clone(),
507 _pd: PhantomData,
508 }
509 }
510}
511
512impl<TYPES: NodeType> DaCertificate<TYPES> {
513 pub fn to_dac2(self) -> DaCertificate2<TYPES> {
515 let data = DaData2 {
516 payload_commit: self.data.payload_commit,
517 next_epoch_payload_commit: None,
518 epoch: None,
519 };
520
521 let bytes: [u8; 32] = self.vote_commitment.into();
522 let vote_commitment = Commitment::from_raw(bytes);
523
524 SimpleCertificate {
525 data,
526 vote_commitment,
527 view_number: self.view_number,
528 signatures: self.signatures.clone(),
529 _pd: PhantomData,
530 }
531 }
532}
533
534impl<TYPES: NodeType> DaCertificate2<TYPES> {
535 pub fn to_dac(self) -> DaCertificate<TYPES> {
537 let data = DaData {
538 payload_commit: self.data.payload_commit,
539 };
540
541 let bytes: [u8; 32] = self.vote_commitment.into();
542 let vote_commitment = Commitment::from_raw(bytes);
543
544 SimpleCertificate {
545 data,
546 vote_commitment,
547 view_number: self.view_number,
548 signatures: self.signatures.clone(),
549 _pd: PhantomData,
550 }
551 }
552}
553
554impl<TYPES: NodeType> ViewSyncPreCommitCertificate<TYPES> {
555 pub fn to_vsc2(self) -> ViewSyncPreCommitCertificate2<TYPES> {
557 let data = ViewSyncPreCommitData2 {
558 relay: self.data.relay,
559 round: self.data.round,
560 epoch: None,
561 };
562
563 let bytes: [u8; 32] = self.vote_commitment.into();
564 let vote_commitment = Commitment::from_raw(bytes);
565
566 SimpleCertificate {
567 data,
568 vote_commitment,
569 view_number: self.view_number,
570 signatures: self.signatures.clone(),
571 _pd: PhantomData,
572 }
573 }
574}
575
576impl<TYPES: NodeType> ViewSyncPreCommitCertificate2<TYPES> {
577 pub fn to_vsc(self) -> ViewSyncPreCommitCertificate<TYPES> {
579 let data = ViewSyncPreCommitData {
580 relay: self.data.relay,
581 round: self.data.round,
582 };
583
584 let bytes: [u8; 32] = self.vote_commitment.into();
585 let vote_commitment = Commitment::from_raw(bytes);
586
587 SimpleCertificate {
588 data,
589 vote_commitment,
590 view_number: self.view_number,
591 signatures: self.signatures.clone(),
592 _pd: PhantomData,
593 }
594 }
595}
596
597impl<TYPES: NodeType> ViewSyncCommitCertificate<TYPES> {
598 pub fn to_vsc2(self) -> ViewSyncCommitCertificate2<TYPES> {
600 let data = ViewSyncCommitData2 {
601 relay: self.data.relay,
602 round: self.data.round,
603 epoch: None,
604 };
605
606 let bytes: [u8; 32] = self.vote_commitment.into();
607 let vote_commitment = Commitment::from_raw(bytes);
608
609 SimpleCertificate {
610 data,
611 vote_commitment,
612 view_number: self.view_number,
613 signatures: self.signatures.clone(),
614 _pd: PhantomData,
615 }
616 }
617}
618
619impl<TYPES: NodeType> ViewSyncCommitCertificate2<TYPES> {
620 pub fn to_vsc(self) -> ViewSyncCommitCertificate<TYPES> {
622 let data = ViewSyncCommitData {
623 relay: self.data.relay,
624 round: self.data.round,
625 };
626
627 let bytes: [u8; 32] = self.vote_commitment.into();
628 let vote_commitment = Commitment::from_raw(bytes);
629
630 SimpleCertificate {
631 data,
632 vote_commitment,
633 view_number: self.view_number,
634 signatures: self.signatures.clone(),
635 _pd: PhantomData,
636 }
637 }
638}
639
640impl<TYPES: NodeType> ViewSyncFinalizeCertificate<TYPES> {
641 pub fn to_vsc2(self) -> ViewSyncFinalizeCertificate2<TYPES> {
643 let data = ViewSyncFinalizeData2 {
644 relay: self.data.relay,
645 round: self.data.round,
646 epoch: None,
647 };
648
649 let bytes: [u8; 32] = self.vote_commitment.into();
650 let vote_commitment = Commitment::from_raw(bytes);
651
652 SimpleCertificate {
653 data,
654 vote_commitment,
655 view_number: self.view_number,
656 signatures: self.signatures.clone(),
657 _pd: PhantomData,
658 }
659 }
660}
661
662impl<TYPES: NodeType> ViewSyncFinalizeCertificate2<TYPES> {
663 pub fn to_vsc(self) -> ViewSyncFinalizeCertificate<TYPES> {
665 let data = ViewSyncFinalizeData {
666 relay: self.data.relay,
667 round: self.data.round,
668 };
669
670 let bytes: [u8; 32] = self.vote_commitment.into();
671 let vote_commitment = Commitment::from_raw(bytes);
672
673 SimpleCertificate {
674 data,
675 vote_commitment,
676 view_number: self.view_number,
677 signatures: self.signatures.clone(),
678 _pd: PhantomData,
679 }
680 }
681}
682
683impl<TYPES: NodeType> TimeoutCertificate<TYPES> {
684 pub fn to_tc2(self) -> TimeoutCertificate2<TYPES> {
686 let data = TimeoutData2 {
687 view: self.data.view,
688 epoch: None,
689 };
690
691 let bytes: [u8; 32] = self.vote_commitment.into();
692 let vote_commitment = Commitment::from_raw(bytes);
693
694 SimpleCertificate {
695 data,
696 vote_commitment,
697 view_number: self.view_number,
698 signatures: self.signatures.clone(),
699 _pd: PhantomData,
700 }
701 }
702}
703
704impl<TYPES: NodeType> TimeoutCertificate2<TYPES> {
705 pub fn to_tc(self) -> TimeoutCertificate<TYPES> {
707 let data = TimeoutData {
708 view: self.data.view,
709 };
710
711 let bytes: [u8; 32] = self.vote_commitment.into();
712 let vote_commitment = Commitment::from_raw(bytes);
713
714 SimpleCertificate {
715 data,
716 vote_commitment,
717 view_number: self.view_number,
718 signatures: self.signatures.clone(),
719 _pd: PhantomData,
720 }
721 }
722}
723
724pub type QuorumCertificate<TYPES> = SimpleCertificate<TYPES, QuorumData<TYPES>, SuccessThreshold>;
726pub type QuorumCertificate2<TYPES> = SimpleCertificate<TYPES, QuorumData2<TYPES>, SuccessThreshold>;
728pub type NextEpochQuorumCertificate2<TYPES> =
730 SimpleCertificate<TYPES, NextEpochQuorumData2<TYPES>, SuccessThreshold>;
731pub type DaCertificate<TYPES> = SimpleCertificate<TYPES, DaData, SuccessThreshold>;
733pub type DaCertificate2<TYPES> = SimpleCertificate<TYPES, DaData2, SuccessThreshold>;
735pub type TimeoutCertificate<TYPES> = SimpleCertificate<TYPES, TimeoutData, SuccessThreshold>;
737pub type TimeoutCertificate2<TYPES> = SimpleCertificate<TYPES, TimeoutData2, SuccessThreshold>;
739pub type ViewSyncPreCommitCertificate<TYPES> =
741 SimpleCertificate<TYPES, ViewSyncPreCommitData, OneHonestThreshold>;
742pub type ViewSyncPreCommitCertificate2<TYPES> =
744 SimpleCertificate<TYPES, ViewSyncPreCommitData2, OneHonestThreshold>;
745pub type ViewSyncCommitCertificate<TYPES> =
747 SimpleCertificate<TYPES, ViewSyncCommitData, SuccessThreshold>;
748pub type ViewSyncCommitCertificate2<TYPES> =
750 SimpleCertificate<TYPES, ViewSyncCommitData2, SuccessThreshold>;
751pub type ViewSyncFinalizeCertificate<TYPES> =
753 SimpleCertificate<TYPES, ViewSyncFinalizeData, SuccessThreshold>;
754pub type ViewSyncFinalizeCertificate2<TYPES> =
756 SimpleCertificate<TYPES, ViewSyncFinalizeData2, SuccessThreshold>;
757pub type UpgradeCertificate<TYPES> =
759 SimpleCertificate<TYPES, UpgradeProposalData, UpgradeThreshold>;
760
761#[derive(Serialize, Deserialize, Eq, Hash, PartialEq, Debug, Clone)]
763pub struct LightClientStateUpdateCertificateV2<TYPES: NodeType> {
764 pub epoch: EpochNumber,
766 pub light_client_state: LightClientState,
768 pub next_stake_table_state: StakeTableState,
770 #[allow(clippy::type_complexity)]
772 pub signatures: Vec<(
773 TYPES::StateSignatureKey,
774 <TYPES::StateSignatureKey as StateSignatureKey>::StateSignature, <TYPES::StateSignatureKey as StateSignatureKey>::StateSignature, )>,
777 pub auth_root: FixedBytes<32>,
782}
783
784#[derive(Serialize, Deserialize, Eq, Hash, PartialEq, Debug, Clone)]
786pub struct LightClientStateUpdateCertificateV1<TYPES: NodeType> {
787 pub epoch: EpochNumber,
789 pub light_client_state: LightClientState,
791 pub next_stake_table_state: StakeTableState,
793 pub signatures: Vec<(
795 TYPES::StateSignatureKey,
796 <TYPES::StateSignatureKey as StateSignatureKey>::StateSignature,
797 )>,
798}
799
800impl<TYPES: NodeType> From<LightClientStateUpdateCertificateV1<TYPES>>
801 for LightClientStateUpdateCertificateV2<TYPES>
802{
803 fn from(v1: LightClientStateUpdateCertificateV1<TYPES>) -> Self {
804 Self {
805 epoch: v1.epoch,
806 light_client_state: v1.light_client_state,
807 next_stake_table_state: v1.next_stake_table_state,
808 signatures: v1
809 .signatures
810 .into_iter()
811 .map(|(key, sig)| (key, sig.clone(), sig)) .collect(),
813 auth_root: Default::default(),
814 }
815 }
816}
817
818impl<TYPES: NodeType> From<LightClientStateUpdateCertificateV2<TYPES>>
819 for LightClientStateUpdateCertificateV1<TYPES>
820{
821 fn from(v2: LightClientStateUpdateCertificateV2<TYPES>) -> Self {
822 Self {
823 epoch: v2.epoch,
824 light_client_state: v2.light_client_state,
825 next_stake_table_state: v2.next_stake_table_state,
826 signatures: v2
827 .signatures
828 .into_iter()
829 .map(|(key, _, sig)| (key, sig))
830 .collect(),
831 }
832 }
833}
834
835impl<TYPES: NodeType> HasViewNumber for LightClientStateUpdateCertificateV2<TYPES> {
836 fn view_number(&self) -> ViewNumber {
837 ViewNumber::new(self.light_client_state.view_number)
838 }
839}
840
841impl<TYPES: NodeType> HasEpoch for LightClientStateUpdateCertificateV2<TYPES> {
842 fn epoch(&self) -> Option<EpochNumber> {
843 Some(self.epoch)
844 }
845}
846
847impl<TYPES: NodeType> LightClientStateUpdateCertificateV1<TYPES> {
848 pub fn genesis() -> Self {
849 Self {
850 epoch: EpochNumber::genesis(),
851 light_client_state: Default::default(),
852 next_stake_table_state: Default::default(),
853 signatures: vec![],
854 }
855 }
856}
857
858impl<TYPES: NodeType> LightClientStateUpdateCertificateV2<TYPES> {
859 pub fn genesis() -> Self {
860 Self {
861 epoch: EpochNumber::genesis(),
862 light_client_state: Default::default(),
863 next_stake_table_state: Default::default(),
864 signatures: vec![],
865 auth_root: Default::default(),
866 }
867 }
868}
869
870#[derive(Serialize, Deserialize, Eq, Hash, PartialEq, Debug, Clone)]
871#[serde(bound(deserialize = "QuorumCertificate2<TYPES>:for<'a> Deserialize<'a>"))]
872pub struct EpochRootQuorumCertificateV2<TYPES: NodeType> {
873 pub qc: QuorumCertificate2<TYPES>,
874 pub state_cert: LightClientStateUpdateCertificateV2<TYPES>,
875}
876
877impl<TYPES: NodeType> HasViewNumber for EpochRootQuorumCertificateV2<TYPES> {
878 fn view_number(&self) -> ViewNumber {
879 self.qc.view_number()
880 }
881}
882
883impl<TYPES: NodeType> HasEpoch for EpochRootQuorumCertificateV2<TYPES> {
884 fn epoch(&self) -> Option<EpochNumber> {
885 self.qc.epoch()
886 }
887}
888
889#[derive(Serialize, Deserialize, Eq, Hash, PartialEq, Debug, Clone)]
890#[serde(bound(deserialize = "QuorumCertificate2<TYPES>:for<'a> Deserialize<'a>"))]
891pub struct EpochRootQuorumCertificateV1<TYPES: NodeType> {
892 pub qc: QuorumCertificate2<TYPES>,
893 pub state_cert: LightClientStateUpdateCertificateV1<TYPES>,
894}
895
896impl<TYPES: NodeType> HasViewNumber for EpochRootQuorumCertificateV1<TYPES> {
897 fn view_number(&self) -> ViewNumber {
898 self.qc.view_number()
899 }
900}
901
902impl<TYPES: NodeType> HasEpoch for EpochRootQuorumCertificateV1<TYPES> {
903 fn epoch(&self) -> Option<EpochNumber> {
904 self.qc.epoch()
905 }
906}
907
908impl<TYPES: NodeType> From<EpochRootQuorumCertificateV1<TYPES>>
909 for EpochRootQuorumCertificateV2<TYPES>
910{
911 fn from(root_qc: EpochRootQuorumCertificateV1<TYPES>) -> Self {
912 Self {
913 qc: root_qc.qc,
914 state_cert: root_qc.state_cert.into(),
915 }
916 }
917}
918
919impl<TYPES: NodeType> From<EpochRootQuorumCertificateV2<TYPES>>
920 for EpochRootQuorumCertificateV1<TYPES>
921{
922 fn from(root_qc: EpochRootQuorumCertificateV2<TYPES>) -> Self {
923 Self {
924 qc: root_qc.qc,
925 state_cert: root_qc.state_cert.into(),
926 }
927 }
928}
929
930#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
936#[serde(bound = "")]
937pub struct CertificatePair<TYPES: NodeType> {
938 qc: QuorumCertificate2<TYPES>,
940
941 next_epoch_qc: Option<NextEpochQuorumCertificate2<TYPES>>,
943}
944
945impl<TYPES: NodeType> CertificatePair<TYPES> {
946 pub fn new(
948 qc: QuorumCertificate2<TYPES>,
949 next_epoch_qc: Option<NextEpochQuorumCertificate2<TYPES>>,
950 ) -> Self {
951 Self { qc, next_epoch_qc }
952 }
953
954 pub fn non_epoch_change(qc: QuorumCertificate2<TYPES>) -> Self {
956 Self::new(qc, None)
957 }
958
959 pub fn for_parent(leaf: &Leaf2<TYPES>) -> Self {
961 Self {
962 qc: leaf.justify_qc(),
963 next_epoch_qc: leaf.next_epoch_justify_qc(),
964 }
965 }
966
967 pub fn qc(&self) -> &QuorumCertificate2<TYPES> {
969 &self.qc
970 }
971
972 pub fn next_epoch_qc(&self) -> Option<&NextEpochQuorumCertificate2<TYPES>> {
974 self.next_epoch_qc.as_ref()
975 }
976
977 pub fn leaf_commit(&self) -> Commitment<Leaf2<TYPES>> {
979 self.qc.data.leaf_commit
980 }
981
982 pub fn epoch(&self) -> Option<EpochNumber> {
986 self.qc.data.epoch
987 }
988
989 pub fn block_number(&self) -> Option<u64> {
993 self.qc.data.block_number
994 }
995
996 pub fn verify_next_epoch_qc(
1006 &self,
1007 epoch_height: u64,
1008 ) -> Result<Option<&NextEpochQuorumCertificate2<TYPES>>> {
1009 let block_number = self.qc.data.block_number.context(warn!(
1010 "QC for epoch {:?} has no block number",
1011 self.qc.data.epoch
1012 ))?;
1013 if !is_epoch_transition(block_number, epoch_height) {
1014 tracing::debug!(
1015 block_number,
1016 epoch_height,
1017 "QC is not in an epoch transition"
1018 );
1019 return Ok(None);
1020 }
1021
1022 let next_epoch_qc = self.next_epoch_qc.as_ref().context(warn!(
1023 "Received High QC for the transition block {block_number} but not the next epoch QC"
1024 ))?;
1025
1026 ensure!(self.qc.view_number == next_epoch_qc.view_number);
1028 ensure!(self.qc.data == *next_epoch_qc.data);
1029
1030 Ok(Some(next_epoch_qc))
1031 }
1032}
1033
1034impl<TYPES: NodeType> HasViewNumber for CertificatePair<TYPES> {
1035 fn view_number(&self) -> ViewNumber {
1036 self.qc.view_number()
1037 }
1038}