1use std::{
13 fmt::{Debug, Display},
14 hash::Hash,
15 marker::PhantomData,
16 sync::Arc,
17 time::Duration,
18};
19
20use async_lock::RwLock;
21use bincode::Options;
22use committable::{Commitment, CommitmentBoundsArkless, Committable, RawCommitmentBuilder};
23use hotshot_utils::anytrace::*;
24use jf_advz::VidScheme;
25use rand::Rng;
26use serde::{Deserialize, Serialize};
27use tagged_base64::{TaggedBase64, Tb64Error};
28use thiserror::Error;
29use vbs::version::{StaticVersionType, Version};
30use vec1::Vec1;
31
32use crate::{
33 drb::DrbResult,
34 epoch_membership::EpochMembershipCoordinator,
35 impl_has_epoch, impl_has_none_epoch,
36 message::{convert_proposal, Proposal, UpgradeLock},
37 simple_certificate::{
38 LightClientStateUpdateCertificateV1, LightClientStateUpdateCertificateV2,
39 NextEpochQuorumCertificate2, QuorumCertificate, QuorumCertificate2, TimeoutCertificate,
40 TimeoutCertificate2, UpgradeCertificate, ViewSyncFinalizeCertificate,
41 ViewSyncFinalizeCertificate2,
42 },
43 simple_vote::{HasEpoch, QuorumData, QuorumData2, UpgradeProposalData, VersionedVoteData},
44 traits::{
45 block_contents::{BlockHeader, BuilderFee, EncodeBytes, TestableBlock},
46 node_implementation::{ConsensusTime, NodeType, Versions},
47 signature_key::SignatureKey,
48 states::TestableState,
49 BlockPayload,
50 },
51 utils::{
52 bincode_opts, genesis_epoch_from_version, option_epoch_from_block_number,
53 EpochTransitionIndicator,
54 },
55 vid::{
56 advz::{advz_scheme, ADVZScheme},
57 avidm::{init_avidm_param, AvidMScheme},
58 avidm_gf2::{init_avidm_gf2_param, AvidmGf2Scheme},
59 },
60 vote::{Certificate, HasViewNumber},
61};
62
63macro_rules! impl_u64_wrapper {
66 ($t:ty, $genesis_val:expr) => {
67 impl ConsensusTime for $t {
68 fn genesis() -> Self {
70 Self($genesis_val)
71 }
72 fn new(n: u64) -> Self {
74 Self(n)
75 }
76 fn u64(&self) -> u64 {
78 self.0
79 }
80 }
81
82 impl Display for $t {
83 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
84 write!(f, "{}", self.0)
85 }
86 }
87
88 impl std::ops::Add<u64> for $t {
89 type Output = $t;
90
91 fn add(self, rhs: u64) -> Self::Output {
92 Self(self.0 + rhs)
93 }
94 }
95
96 impl std::ops::AddAssign<u64> for $t {
97 fn add_assign(&mut self, rhs: u64) {
98 self.0 += rhs;
99 }
100 }
101
102 impl std::ops::Deref for $t {
103 type Target = u64;
104
105 fn deref(&self) -> &Self::Target {
106 &self.0
107 }
108 }
109
110 impl std::ops::Sub<u64> for $t {
111 type Output = $t;
112 fn sub(self, rhs: u64) -> Self::Output {
113 Self(self.0 - rhs)
114 }
115 }
116 };
117}
118
119#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
121pub struct ViewNumber(u64);
122
123impl Committable for ViewNumber {
124 fn commit(&self) -> Commitment<Self> {
125 let builder = RawCommitmentBuilder::new("View Number Commitment");
126 builder.u64(self.0).finalize()
127 }
128}
129
130impl_u64_wrapper!(ViewNumber, 0u64);
131
132#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
134pub struct EpochNumber(u64);
135
136impl Committable for EpochNumber {
137 fn commit(&self) -> Commitment<Self> {
138 let builder = RawCommitmentBuilder::new("Epoch Number Commitment");
139 builder.u64(self.0).finalize()
140 }
141}
142
143impl_u64_wrapper!(EpochNumber, 1u64);
144
145#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
147#[serde(bound = "TYPES: NodeType")]
148pub struct DaProposal<TYPES: NodeType> {
149 pub encoded_transactions: Arc<[u8]>,
151 pub metadata: <TYPES::BlockPayload as BlockPayload<TYPES>>::Metadata,
153 pub view_number: TYPES::View,
155}
156
157#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
159#[serde(bound = "TYPES: NodeType")]
160pub struct DaProposal2<TYPES: NodeType> {
161 pub encoded_transactions: Arc<[u8]>,
163 pub metadata: <TYPES::BlockPayload as BlockPayload<TYPES>>::Metadata,
165 pub view_number: TYPES::View,
167 pub epoch: Option<TYPES::Epoch>,
169 pub epoch_transition_indicator: EpochTransitionIndicator,
172}
173
174impl<TYPES: NodeType> From<DaProposal<TYPES>> for DaProposal2<TYPES> {
175 fn from(da_proposal: DaProposal<TYPES>) -> Self {
176 Self {
177 encoded_transactions: da_proposal.encoded_transactions,
178 metadata: da_proposal.metadata,
179 view_number: da_proposal.view_number,
180 epoch: None,
181 epoch_transition_indicator: EpochTransitionIndicator::NotInTransition,
182 }
183 }
184}
185
186impl<TYPES: NodeType> From<DaProposal2<TYPES>> for DaProposal<TYPES> {
187 fn from(da_proposal2: DaProposal2<TYPES>) -> Self {
188 Self {
189 encoded_transactions: da_proposal2.encoded_transactions,
190 metadata: da_proposal2.metadata,
191 view_number: da_proposal2.view_number,
192 }
193 }
194}
195
196#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
198#[serde(bound = "TYPES: NodeType")]
199pub struct UpgradeProposal<TYPES>
200where
201 TYPES: NodeType,
202{
203 pub upgrade_proposal: UpgradeProposalData<TYPES>,
205 pub view_number: TYPES::View,
207}
208
209pub type VidCommitment0 = crate::vid::advz::ADVZCommitment;
211pub type VidCommitment1 = crate::vid::avidm::AvidMCommitment;
212pub type VidCommitment2 = crate::vid::avidm_gf2::AvidmGf2Commitment;
213
214#[derive(Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize, Ord, PartialOrd)]
216#[serde(
217 try_from = "tagged_base64::TaggedBase64",
218 into = "tagged_base64::TaggedBase64"
219)]
220pub enum VidCommitment {
221 V0(VidCommitment0),
222 V1(VidCommitment1),
223 V2(VidCommitment2),
224}
225
226impl Default for VidCommitment {
227 fn default() -> Self {
228 Self::V0(Default::default())
229 }
230}
231
232impl Display for VidCommitment {
233 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
234 std::write!(f, "{}", TaggedBase64::from(self))
235 }
236}
237
238impl Debug for VidCommitment {
239 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
240 std::fmt::Display::fmt(self, f)
241 }
242}
243
244impl From<VidCommitment> for TaggedBase64 {
245 fn from(val: VidCommitment) -> Self {
246 match val {
247 VidCommitment::V0(comm) => comm.into(),
248 VidCommitment::V1(comm) => comm.into(),
249 VidCommitment::V2(comm) => comm.into(),
250 }
251 }
252}
253
254impl From<&VidCommitment> for TaggedBase64 {
255 fn from(val: &VidCommitment) -> Self {
256 match val {
257 VidCommitment::V0(comm) => comm.into(),
258 VidCommitment::V1(comm) => comm.into(),
259 VidCommitment::V2(comm) => comm.into(),
260 }
261 }
262}
263
264impl TryFrom<TaggedBase64> for VidCommitment {
265 type Error = tagged_base64::Tb64Error;
266
267 fn try_from(value: TaggedBase64) -> std::result::Result<Self, Self::Error> {
268 match value.tag().as_str() {
269 "HASH" => VidCommitment0::try_from(value).map(Self::V0),
270 "AvidMCommit" => VidCommitment1::try_from(value).map(Self::V1),
271 "AvidmGf2Commit" => VidCommitment2::try_from(value).map(Self::V2),
272 _ => Err(Tb64Error::InvalidTag),
273 }
274 }
275}
276
277impl<'a> TryFrom<&'a TaggedBase64> for VidCommitment {
278 type Error = tagged_base64::Tb64Error;
279
280 fn try_from(value: &'a TaggedBase64) -> std::result::Result<Self, Self::Error> {
281 match value.tag().as_str() {
282 "HASH" => VidCommitment0::try_from(value).map(Self::V0),
283 "AvidMCommit" => VidCommitment1::try_from(value).map(Self::V1),
284 "AvidmGf2Commit" => VidCommitment2::try_from(value).map(Self::V2),
285 _ => Err(Tb64Error::InvalidTag),
286 }
287 }
288}
289
290impl std::str::FromStr for VidCommitment {
291 type Err = tagged_base64::Tb64Error;
292 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
293 use core::convert::TryFrom;
294 Self::try_from(TaggedBase64::from_str(s)?)
295 .map_err(|_| tagged_base64::Tb64Error::InvalidData)
296 }
297}
298
299impl From<VidCommitment1> for VidCommitment {
307 fn from(comm: VidCommitment1) -> Self {
308 Self::V1(comm)
309 }
310}
311
312impl From<VidCommitment2> for VidCommitment {
313 fn from(comm: VidCommitment2) -> Self {
314 Self::V2(comm)
315 }
316}
317
318impl AsRef<[u8]> for VidCommitment {
319 fn as_ref(&self) -> &[u8] {
320 match self {
321 Self::V0(comm) => comm.as_ref(),
322 Self::V1(comm) => comm.as_ref(),
323 Self::V2(comm) => comm.as_ref(),
324 }
325 }
326}
327
328impl AsRef<[u8; 32]> for VidCommitment {
329 fn as_ref(&self) -> &[u8; 32] {
330 match self {
331 Self::V0(comm) => comm.as_ref().as_ref(),
332 Self::V1(comm) => comm.as_ref(),
333 Self::V2(comm) => comm.as_ref(),
334 }
335 }
336}
337
338#[must_use]
343#[allow(clippy::panic)]
344pub fn vid_commitment<V: Versions>(
345 encoded_transactions: &[u8],
346 metadata: &[u8],
347 total_weight: usize,
348 version: Version,
349) -> VidCommitment {
350 if version < V::Epochs::VERSION {
351 let encoded_tx_len = encoded_transactions.len();
352 advz_scheme(total_weight)
353 .commit_only(encoded_transactions)
354 .map(VidCommitment::V0)
355 .unwrap_or_else(|err| {
356 panic!(
357 "VidScheme::commit_only \
358 failure:(total_weight,payload_byte_len)=({total_weight},{encoded_tx_len}) \
359 error: {err}"
360 )
361 })
362 } else if version < V::Vid2Upgrade::VERSION {
363 let param = init_avidm_param(total_weight).unwrap();
364 let encoded_tx_len = encoded_transactions.len();
365 AvidMScheme::commit(
366 ¶m,
367 encoded_transactions,
368 ns_table::parse_ns_table(encoded_tx_len, metadata),
369 )
370 .map(VidCommitment::V1)
371 .unwrap()
372 } else {
373 let param = init_avidm_gf2_param(total_weight).unwrap();
374 let encoded_tx_len = encoded_transactions.len();
375 AvidmGf2Scheme::commit(
376 ¶m,
377 encoded_transactions,
378 ns_table::parse_ns_table(encoded_tx_len, metadata),
379 )
380 .map(|(comm, _)| VidCommitment::V2(comm))
381 .unwrap()
382 }
383}
384
385pub type VidCommon0 = crate::vid::advz::ADVZCommon;
387pub type VidCommon1 = crate::vid::avidm::AvidMCommon;
388pub type VidCommon2 = crate::vid::avidm_gf2::AvidmGf2Common;
389
390#[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq)]
392pub enum VidCommon {
393 V0(VidCommon0),
394 V1(VidCommon1),
395 V2(VidCommon2),
396}
397
398impl From<VidCommon1> for VidCommon {
399 fn from(comm: VidCommon1) -> Self {
400 Self::V1(comm)
401 }
402}
403
404impl From<VidCommon2> for VidCommon {
405 fn from(comm: VidCommon2) -> Self {
406 Self::V2(comm)
407 }
408}
409
410impl VidCommon {
411 pub fn is_consistent(&self, comm: &VidCommitment) -> bool {
412 match (self, comm) {
413 (Self::V0(common), VidCommitment::V0(comm)) => {
414 ADVZScheme::is_consistent(comm, common).is_ok()
415 },
416 (Self::V1(_), VidCommitment::V1(_)) => true,
417 (Self::V2(common), VidCommitment::V2(comm)) => {
418 AvidmGf2Scheme::is_consistent(comm, common)
419 },
420 _ => false,
421 }
422 }
423}
424
425pub type VidShare0 = crate::vid::advz::ADVZShare;
427pub type VidShare1 = crate::vid::avidm::AvidMShare;
428pub type VidShare2 = crate::vid::avidm_gf2::AvidmGf2Share;
429
430#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
432pub enum VidShare {
433 V0(VidShare0),
434 V1(VidShare1),
435 V2(VidShare2),
436}
437
438impl From<VidShare1> for VidShare {
446 fn from(share: VidShare1) -> Self {
447 Self::V1(share)
448 }
449}
450
451impl From<VidShare2> for VidShare {
452 fn from(share: VidShare2) -> Self {
453 Self::V2(share)
454 }
455}
456
457pub mod ns_table;
458pub mod vid_disperse;
459
460pub struct VidDisperseAndDuration<TYPES: NodeType> {
462 pub disperse: VidDisperse<TYPES>,
464 pub duration: Duration,
466}
467
468pub type VidDisperse0<TYPES> = vid_disperse::ADVZDisperse<TYPES>;
470pub type VidDisperse1<TYPES> = vid_disperse::AvidMDisperse<TYPES>;
471pub type VidDisperse2<TYPES> = vid_disperse::AvidmGf2Disperse<TYPES>;
472
473#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
479#[serde(bound = "TYPES: NodeType")]
480pub enum VidDisperse<TYPES: NodeType> {
481 V0(VidDisperse0<TYPES>),
483 V1(VidDisperse1<TYPES>),
485 V2(VidDisperse2<TYPES>),
487}
488
489impl<TYPES: NodeType> From<VidDisperse0<TYPES>> for VidDisperse<TYPES> {
490 fn from(disperse: VidDisperse0<TYPES>) -> Self {
491 Self::V0(disperse)
492 }
493}
494
495impl<TYPES: NodeType> From<VidDisperse1<TYPES>> for VidDisperse<TYPES> {
496 fn from(disperse: VidDisperse1<TYPES>) -> Self {
497 Self::V1(disperse)
498 }
499}
500
501impl<TYPES: NodeType> From<VidDisperse2<TYPES>> for VidDisperse<TYPES> {
502 fn from(disperse: VidDisperse2<TYPES>) -> Self {
503 Self::V2(disperse)
504 }
505}
506
507impl<TYPES: NodeType> HasViewNumber<TYPES> for VidDisperse<TYPES> {
508 fn view_number(&self) -> TYPES::View {
509 match self {
510 Self::V0(disperse) => disperse.view_number(),
511 Self::V1(disperse) => disperse.view_number(),
512 Self::V2(disperse) => disperse.view_number(),
513 }
514 }
515}
516
517impl<TYPES: NodeType> HasEpoch<TYPES> for VidDisperse<TYPES> {
518 fn epoch(&self) -> Option<TYPES::Epoch> {
519 match self {
520 Self::V0(disperse) => disperse.epoch(),
521 Self::V1(disperse) => disperse.epoch(),
522 Self::V2(disperse) => disperse.epoch(),
523 }
524 }
525}
526
527impl<TYPES: NodeType> VidDisperse<TYPES> {
528 #[allow(clippy::panic)]
534 pub async fn calculate_vid_disperse<V: Versions>(
535 payload: &TYPES::BlockPayload,
536 membership: &EpochMembershipCoordinator<TYPES>,
537 view: TYPES::View,
538 target_epoch: Option<TYPES::Epoch>,
539 data_epoch: Option<TYPES::Epoch>,
540 metadata: &<TYPES::BlockPayload as BlockPayload<TYPES>>::Metadata,
541 upgrade_lock: &UpgradeLock<TYPES, V>,
542 ) -> Result<VidDisperseAndDuration<TYPES>> {
543 let epochs_enabled = upgrade_lock.epochs_enabled(view).await;
544 let upgraded_vid2 = upgrade_lock.upgraded_vid2(view).await;
545 if upgraded_vid2 {
546 VidDisperse2::calculate_vid_disperse(
547 payload,
548 membership,
549 view,
550 target_epoch,
551 data_epoch,
552 metadata,
553 )
554 .await
555 .map(|(disperse, duration)| VidDisperseAndDuration {
556 disperse: Self::V2(disperse),
557 duration,
558 })
559 } else if epochs_enabled {
560 VidDisperse1::calculate_vid_disperse(
561 payload,
562 membership,
563 view,
564 target_epoch,
565 data_epoch,
566 metadata,
567 )
568 .await
569 .map(|(disperse, duration)| VidDisperseAndDuration {
570 disperse: Self::V1(disperse),
571 duration,
572 })
573 } else {
574 VidDisperse0::calculate_vid_disperse(
575 payload,
576 membership,
577 view,
578 target_epoch,
579 data_epoch,
580 )
581 .await
582 .map(|(disperse, duration)| VidDisperseAndDuration {
583 disperse: Self::V0(disperse),
584 duration,
585 })
586 }
587 }
588
589 pub fn payload_commitment(&self) -> VidCommitment {
591 match self {
592 Self::V0(disperse) => VidCommitment::V0(disperse.payload_commitment),
593 Self::V1(disperse) => disperse.payload_commitment.into(),
594 Self::V2(disperse) => disperse.payload_commitment.into(),
595 }
596 }
597
598 pub fn payload_commitment_ref(&self) -> &[u8] {
600 match self {
601 Self::V0(disperse) => disperse.payload_commitment.as_ref(),
602 Self::V1(disperse) => disperse.payload_commitment.as_ref(),
603 Self::V2(disperse) => disperse.payload_commitment.as_ref(),
604 }
605 }
606
607 pub fn set_view_number(&mut self, view_number: <TYPES as NodeType>::View) {
609 match self {
610 Self::V0(share) => share.view_number = view_number,
611 Self::V1(share) => share.view_number = view_number,
612 Self::V2(share) => share.view_number = view_number,
613 }
614 }
615
616 pub fn to_shares(self) -> Vec<VidDisperseShare<TYPES>> {
617 match self {
618 VidDisperse::V0(disperse) => disperse
619 .to_shares()
620 .into_iter()
621 .map(|share| VidDisperseShare::V0(share))
622 .collect(),
623 VidDisperse::V1(disperse) => disperse
624 .to_shares()
625 .into_iter()
626 .map(|share| VidDisperseShare::V1(share))
627 .collect(),
628 VidDisperse::V2(disperse) => disperse
629 .to_shares()
630 .into_iter()
631 .map(|share| VidDisperseShare::V2(share))
632 .collect(),
633 }
634 }
635
636 pub fn to_share_proposals(
638 proposal: Proposal<TYPES, Self>,
639 ) -> Vec<Proposal<TYPES, VidDisperseShare<TYPES>>> {
640 match proposal.data {
641 VidDisperse::V0(disperse) => disperse
642 .to_share_proposals(&proposal.signature)
643 .into_iter()
644 .map(|proposal| convert_proposal(proposal))
645 .collect(),
646 VidDisperse::V1(disperse) => disperse
647 .to_share_proposals(&proposal.signature)
648 .into_iter()
649 .map(|proposal| convert_proposal(proposal))
650 .collect(),
651 VidDisperse::V2(disperse) => disperse
652 .to_share_proposals(&proposal.signature)
653 .into_iter()
654 .map(|proposal| convert_proposal(proposal))
655 .collect(),
656 }
657 }
658}
659
660pub type VidDisperseShare0<TYPES> = vid_disperse::ADVZDisperseShare<TYPES>;
662pub type VidDisperseShare1<TYPES> = vid_disperse::AvidMDisperseShare<TYPES>;
663pub type VidDisperseShare2<TYPES> = vid_disperse::AvidmGf2DisperseShare<TYPES>;
664
665#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
667#[serde(bound = "TYPES: NodeType")]
668pub enum VidDisperseShare<TYPES: NodeType> {
669 V0(VidDisperseShare0<TYPES>),
671 V1(VidDisperseShare1<TYPES>),
673 V2(VidDisperseShare2<TYPES>),
675}
676
677impl<TYPES: NodeType> From<VidDisperseShare0<TYPES>> for VidDisperseShare<TYPES> {
678 fn from(share: VidDisperseShare0<TYPES>) -> Self {
679 Self::V0(share)
680 }
681}
682
683impl<TYPES: NodeType> From<VidDisperseShare1<TYPES>> for VidDisperseShare<TYPES> {
684 fn from(share: VidDisperseShare1<TYPES>) -> Self {
685 Self::V1(share)
686 }
687}
688
689impl<TYPES: NodeType> From<VidDisperseShare2<TYPES>> for VidDisperseShare<TYPES> {
690 fn from(share: VidDisperseShare2<TYPES>) -> Self {
691 Self::V2(share)
692 }
693}
694
695impl<TYPES: NodeType> VidDisperseShare<TYPES> {
696 pub fn to_proposal(
698 self,
699 private_key: &<TYPES::SignatureKey as SignatureKey>::PrivateKey,
700 ) -> Option<Proposal<TYPES, Self>> {
701 let payload_commitment_ref: &[u8] = match &self {
702 Self::V0(share) => share.payload_commitment.as_ref(),
703 Self::V1(share) => share.payload_commitment.as_ref(),
704 Self::V2(share) => share.payload_commitment.as_ref(),
705 };
706 let Ok(signature) = TYPES::SignatureKey::sign(private_key, payload_commitment_ref) else {
707 tracing::error!("VID: failed to sign dispersal share payload");
708 return None;
709 };
710 Some(Proposal {
711 signature,
712 _pd: PhantomData,
713 data: self,
714 })
715 }
716
717 pub fn recipient_key(&self) -> &TYPES::SignatureKey {
719 match self {
720 Self::V0(share) => &share.recipient_key,
721 Self::V1(share) => &share.recipient_key,
722 Self::V2(share) => &share.recipient_key,
723 }
724 }
725
726 pub fn payload_byte_len(&self) -> u32 {
728 match self {
729 Self::V0(share) => share.payload_byte_len(),
730 Self::V1(share) => share.payload_byte_len(),
731 Self::V2(share) => share.payload_byte_len(),
732 }
733 }
734
735 pub fn payload_commitment_ref(&self) -> &[u8] {
737 match self {
738 Self::V0(share) => share.payload_commitment.as_ref(),
739 Self::V1(share) => share.payload_commitment.as_ref(),
740 Self::V2(share) => share.payload_commitment.as_ref(),
741 }
742 }
743
744 pub fn payload_commitment(&self) -> VidCommitment {
746 match self {
747 Self::V0(share) => VidCommitment::V0(share.payload_commitment),
748 Self::V1(share) => share.payload_commitment.into(),
749 Self::V2(share) => share.payload_commitment.into(),
750 }
751 }
752
753 pub fn target_epoch(&self) -> Option<<TYPES as NodeType>::Epoch> {
755 match self {
756 Self::V0(_) => None,
757 Self::V1(share) => share.target_epoch,
758 Self::V2(share) => share.target_epoch,
759 }
760 }
761
762 pub fn verify(&self, total_nodes: usize) -> bool {
764 match self {
765 Self::V0(share) => share.verify(total_nodes),
766 Self::V1(share) => share.verify(total_nodes),
767 Self::V2(share) => share.verify(total_nodes),
768 }
769 }
770
771 pub fn set_view_number(&mut self, view_number: <TYPES as NodeType>::View) {
773 match self {
774 Self::V0(share) => share.view_number = view_number,
775 Self::V1(share) => share.view_number = view_number,
776 Self::V2(share) => share.view_number = view_number,
777 }
778 }
779}
780
781impl<TYPES: NodeType> HasViewNumber<TYPES> for VidDisperseShare<TYPES> {
782 fn view_number(&self) -> TYPES::View {
783 match self {
784 Self::V0(disperse) => disperse.view_number(),
785 Self::V1(disperse) => disperse.view_number(),
786 Self::V2(disperse) => disperse.view_number(),
787 }
788 }
789}
790
791impl<TYPES: NodeType> HasEpoch<TYPES> for VidDisperseShare<TYPES> {
792 fn epoch(&self) -> Option<TYPES::Epoch> {
793 match self {
794 Self::V0(_) => None,
795 Self::V1(share) => share.epoch(),
796 Self::V2(share) => share.epoch(),
797 }
798 }
799}
800
801#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
804#[serde(bound(deserialize = ""))]
805pub enum ViewChangeEvidence<TYPES: NodeType> {
806 Timeout(TimeoutCertificate<TYPES>),
808 ViewSync(ViewSyncFinalizeCertificate<TYPES>),
810}
811
812impl<TYPES: NodeType> ViewChangeEvidence<TYPES> {
813 pub fn is_valid_for_view(&self, view: &TYPES::View) -> bool {
815 match self {
816 ViewChangeEvidence::Timeout(timeout_cert) => timeout_cert.data().view == *view - 1,
817 ViewChangeEvidence::ViewSync(view_sync_cert) => view_sync_cert.view_number == *view,
818 }
819 }
820
821 pub fn to_evidence2(self) -> ViewChangeEvidence2<TYPES> {
823 match self {
824 ViewChangeEvidence::Timeout(timeout_cert) => {
825 ViewChangeEvidence2::Timeout(timeout_cert.to_tc2())
826 },
827 ViewChangeEvidence::ViewSync(view_sync_cert) => {
828 ViewChangeEvidence2::ViewSync(view_sync_cert.to_vsc2())
829 },
830 }
831 }
832}
833
834#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
837#[serde(bound(deserialize = ""))]
838pub enum ViewChangeEvidence2<TYPES: NodeType> {
839 Timeout(TimeoutCertificate2<TYPES>),
841 ViewSync(ViewSyncFinalizeCertificate2<TYPES>),
843}
844
845impl<TYPES: NodeType> ViewChangeEvidence2<TYPES> {
846 pub fn is_valid_for_view(&self, view: &TYPES::View) -> bool {
848 match self {
849 ViewChangeEvidence2::Timeout(timeout_cert) => timeout_cert.data().view == *view - 1,
850 ViewChangeEvidence2::ViewSync(view_sync_cert) => view_sync_cert.view_number == *view,
851 }
852 }
853
854 pub fn to_evidence(self) -> ViewChangeEvidence<TYPES> {
856 match self {
857 ViewChangeEvidence2::Timeout(timeout_cert) => {
858 ViewChangeEvidence::Timeout(timeout_cert.to_tc())
859 },
860 ViewChangeEvidence2::ViewSync(view_sync_cert) => {
861 ViewChangeEvidence::ViewSync(view_sync_cert.to_vsc())
862 },
863 }
864 }
865}
866
867#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
869#[serde(bound(deserialize = ""))]
870pub struct QuorumProposal<TYPES: NodeType> {
871 pub block_header: TYPES::BlockHeader,
873
874 pub view_number: TYPES::View,
876
877 pub justify_qc: QuorumCertificate<TYPES>,
879
880 pub upgrade_certificate: Option<UpgradeCertificate<TYPES>>,
882
883 pub proposal_certificate: Option<ViewChangeEvidence<TYPES>>,
888}
889
890#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
892#[serde(bound(deserialize = ""))]
893pub struct QuorumProposal2<TYPES: NodeType> {
894 pub block_header: TYPES::BlockHeader,
896
897 pub view_number: TYPES::View,
899
900 pub epoch: Option<TYPES::Epoch>,
902
903 pub justify_qc: QuorumCertificate2<TYPES>,
905
906 pub next_epoch_justify_qc: Option<NextEpochQuorumCertificate2<TYPES>>,
908
909 pub upgrade_certificate: Option<UpgradeCertificate<TYPES>>,
911
912 pub view_change_evidence: Option<ViewChangeEvidence2<TYPES>>,
914
915 #[serde(with = "serde_bytes")]
920 pub next_drb_result: Option<DrbResult>,
921
922 pub state_cert: Option<LightClientStateUpdateCertificateV2<TYPES>>,
925}
926
927#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
936#[serde(bound(deserialize = ""))]
937pub struct QuorumProposal2Legacy<TYPES: NodeType> {
938 pub block_header: TYPES::BlockHeader,
940
941 pub view_number: TYPES::View,
943
944 pub epoch: Option<TYPES::Epoch>,
946
947 pub justify_qc: QuorumCertificate2<TYPES>,
949
950 pub next_epoch_justify_qc: Option<NextEpochQuorumCertificate2<TYPES>>,
952
953 pub upgrade_certificate: Option<UpgradeCertificate<TYPES>>,
955
956 pub view_change_evidence: Option<ViewChangeEvidence2<TYPES>>,
958
959 #[serde(with = "serde_bytes")]
964 pub next_drb_result: Option<DrbResult>,
965
966 pub state_cert: Option<LightClientStateUpdateCertificateV1<TYPES>>,
970}
971
972impl<TYPES: NodeType> From<QuorumProposal2Legacy<TYPES>> for QuorumProposal2<TYPES> {
973 fn from(quorum_proposal2: QuorumProposal2Legacy<TYPES>) -> Self {
974 Self {
975 block_header: quorum_proposal2.block_header,
976 view_number: quorum_proposal2.view_number,
977 epoch: quorum_proposal2.epoch,
978 justify_qc: quorum_proposal2.justify_qc,
979 next_epoch_justify_qc: quorum_proposal2.next_epoch_justify_qc,
980 upgrade_certificate: quorum_proposal2.upgrade_certificate,
981 view_change_evidence: quorum_proposal2.view_change_evidence,
982 next_drb_result: quorum_proposal2.next_drb_result,
983 state_cert: quorum_proposal2.state_cert.map(Into::into),
984 }
985 }
986}
987
988impl<TYPES: NodeType> From<QuorumProposal2<TYPES>> for QuorumProposal2Legacy<TYPES> {
989 fn from(quorum_proposal2: QuorumProposal2<TYPES>) -> Self {
990 Self {
991 block_header: quorum_proposal2.block_header,
992 view_number: quorum_proposal2.view_number,
993 epoch: quorum_proposal2.epoch,
994 justify_qc: quorum_proposal2.justify_qc,
995 next_epoch_justify_qc: quorum_proposal2.next_epoch_justify_qc,
996 upgrade_certificate: quorum_proposal2.upgrade_certificate,
997 view_change_evidence: quorum_proposal2.view_change_evidence,
998 next_drb_result: quorum_proposal2.next_drb_result,
999 state_cert: quorum_proposal2.state_cert.map(Into::into),
1000 }
1001 }
1002}
1003
1004#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
1010#[serde(bound(deserialize = ""))]
1011pub struct QuorumProposalWrapperLegacy<TYPES: NodeType> {
1012 pub proposal: QuorumProposal2Legacy<TYPES>,
1014}
1015
1016#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
1018#[serde(bound(deserialize = ""))]
1019pub struct QuorumProposalWrapper<TYPES: NodeType> {
1020 pub proposal: QuorumProposal2<TYPES>,
1022}
1023
1024impl<TYPES: NodeType> From<QuorumProposalWrapperLegacy<TYPES>> for QuorumProposalWrapper<TYPES> {
1025 fn from(v3: QuorumProposalWrapperLegacy<TYPES>) -> Self {
1026 Self {
1027 proposal: v3.proposal.into(),
1028 }
1029 }
1030}
1031
1032impl<TYPES: NodeType> QuorumProposal2<TYPES> {
1033 pub async fn validate_epoch<V: Versions>(
1037 &self,
1038 upgrade_lock: &UpgradeLock<TYPES, V>,
1039 epoch_height: u64,
1040 ) -> Result<()> {
1041 let calculated_epoch = option_epoch_from_block_number::<TYPES>(
1042 upgrade_lock.epochs_enabled(self.view_number()).await,
1043 self.block_header.block_number(),
1044 epoch_height,
1045 );
1046 ensure!(
1047 calculated_epoch == self.epoch(),
1048 "Quorum proposal invalid: inconsistent epoch."
1049 );
1050 Ok(())
1051 }
1052}
1053
1054impl<TYPES: NodeType> QuorumProposalWrapper<TYPES> {
1055 pub fn block_header(&self) -> &TYPES::BlockHeader {
1057 &self.proposal.block_header
1058 }
1059
1060 pub fn view_number(&self) -> TYPES::View {
1062 self.proposal.view_number
1063 }
1064
1065 pub fn justify_qc(&self) -> &QuorumCertificate2<TYPES> {
1067 &self.proposal.justify_qc
1068 }
1069
1070 pub fn next_epoch_justify_qc(&self) -> &Option<NextEpochQuorumCertificate2<TYPES>> {
1072 &self.proposal.next_epoch_justify_qc
1073 }
1074
1075 pub fn upgrade_certificate(&self) -> &Option<UpgradeCertificate<TYPES>> {
1077 &self.proposal.upgrade_certificate
1078 }
1079
1080 pub fn view_change_evidence(&self) -> &Option<ViewChangeEvidence2<TYPES>> {
1082 &self.proposal.view_change_evidence
1083 }
1084
1085 pub fn next_drb_result(&self) -> &Option<DrbResult> {
1087 &self.proposal.next_drb_result
1088 }
1089
1090 pub async fn validate_epoch<V: Versions>(
1094 &self,
1095 upgrade_lock: &UpgradeLock<TYPES, V>,
1096 epoch_height: u64,
1097 ) -> Result<()> {
1098 self.proposal
1099 .validate_epoch(upgrade_lock, epoch_height)
1100 .await
1101 }
1102
1103 pub fn state_cert(&self) -> &Option<LightClientStateUpdateCertificateV2<TYPES>> {
1105 &self.proposal.state_cert
1106 }
1107}
1108
1109impl<TYPES: NodeType> From<QuorumProposal<TYPES>> for QuorumProposalWrapper<TYPES> {
1110 fn from(quorum_proposal: QuorumProposal<TYPES>) -> Self {
1111 Self {
1112 proposal: quorum_proposal.into(),
1113 }
1114 }
1115}
1116
1117impl<TYPES: NodeType> From<QuorumProposal2Legacy<TYPES>> for QuorumProposalWrapper<TYPES> {
1118 fn from(quorum_proposal: QuorumProposal2Legacy<TYPES>) -> Self {
1119 Self {
1120 proposal: quorum_proposal.into(),
1121 }
1122 }
1123}
1124
1125impl<TYPES: NodeType> From<QuorumProposal2<TYPES>> for QuorumProposalWrapper<TYPES> {
1126 fn from(quorum_proposal2: QuorumProposal2<TYPES>) -> Self {
1127 Self {
1128 proposal: quorum_proposal2,
1129 }
1130 }
1131}
1132
1133impl<TYPES: NodeType> From<QuorumProposalWrapper<TYPES>> for QuorumProposal<TYPES> {
1134 fn from(quorum_proposal_wrapper: QuorumProposalWrapper<TYPES>) -> Self {
1135 quorum_proposal_wrapper.proposal.into()
1136 }
1137}
1138
1139impl<TYPES: NodeType> From<QuorumProposalWrapper<TYPES>> for QuorumProposal2Legacy<TYPES> {
1140 fn from(quorum_proposal_wrapper: QuorumProposalWrapper<TYPES>) -> Self {
1141 quorum_proposal_wrapper.proposal.into()
1142 }
1143}
1144
1145impl<TYPES: NodeType> From<QuorumProposalWrapper<TYPES>> for QuorumProposal2<TYPES> {
1146 fn from(quorum_proposal_wrapper: QuorumProposalWrapper<TYPES>) -> Self {
1147 quorum_proposal_wrapper.proposal
1148 }
1149}
1150
1151impl<TYPES: NodeType> From<QuorumProposal<TYPES>> for QuorumProposal2<TYPES> {
1152 fn from(quorum_proposal: QuorumProposal<TYPES>) -> Self {
1153 Self {
1154 block_header: quorum_proposal.block_header,
1155 view_number: quorum_proposal.view_number,
1156 epoch: None,
1157 justify_qc: quorum_proposal.justify_qc.to_qc2(),
1158 next_epoch_justify_qc: None,
1159 upgrade_certificate: quorum_proposal.upgrade_certificate,
1160 view_change_evidence: quorum_proposal
1161 .proposal_certificate
1162 .map(ViewChangeEvidence::to_evidence2),
1163 next_drb_result: None,
1164 state_cert: None,
1165 }
1166 }
1167}
1168
1169impl<TYPES: NodeType> From<QuorumProposal2<TYPES>> for QuorumProposal<TYPES> {
1170 fn from(quorum_proposal2: QuorumProposal2<TYPES>) -> Self {
1171 Self {
1172 block_header: quorum_proposal2.block_header,
1173 view_number: quorum_proposal2.view_number,
1174 justify_qc: quorum_proposal2.justify_qc.to_qc(),
1175 upgrade_certificate: quorum_proposal2.upgrade_certificate,
1176 proposal_certificate: quorum_proposal2
1177 .view_change_evidence
1178 .map(ViewChangeEvidence2::to_evidence),
1179 }
1180 }
1181}
1182
1183impl<TYPES: NodeType> From<Leaf<TYPES>> for Leaf2<TYPES> {
1184 fn from(leaf: Leaf<TYPES>) -> Self {
1185 let bytes: [u8; 32] = leaf.parent_commitment.into();
1186
1187 Self {
1188 view_number: leaf.view_number,
1189 justify_qc: leaf.justify_qc.to_qc2(),
1190 next_epoch_justify_qc: None,
1191 parent_commitment: Commitment::from_raw(bytes),
1192 block_header: leaf.block_header,
1193 upgrade_certificate: leaf.upgrade_certificate,
1194 block_payload: leaf.block_payload,
1195 view_change_evidence: None,
1196 next_drb_result: None,
1197 with_epoch: false,
1198 }
1199 }
1200}
1201
1202impl<TYPES: NodeType> HasViewNumber<TYPES> for DaProposal<TYPES> {
1203 fn view_number(&self) -> TYPES::View {
1204 self.view_number
1205 }
1206}
1207
1208impl<TYPES: NodeType> HasViewNumber<TYPES> for DaProposal2<TYPES> {
1209 fn view_number(&self) -> TYPES::View {
1210 self.view_number
1211 }
1212}
1213
1214impl<TYPES: NodeType> HasViewNumber<TYPES> for QuorumProposal<TYPES> {
1215 fn view_number(&self) -> TYPES::View {
1216 self.view_number
1217 }
1218}
1219
1220impl<TYPES: NodeType> HasViewNumber<TYPES> for QuorumProposal2<TYPES> {
1221 fn view_number(&self) -> TYPES::View {
1222 self.view_number
1223 }
1224}
1225
1226impl<TYPES: NodeType> HasViewNumber<TYPES> for QuorumProposal2Legacy<TYPES> {
1227 fn view_number(&self) -> TYPES::View {
1228 self.view_number
1229 }
1230}
1231
1232impl<TYPES: NodeType> HasViewNumber<TYPES> for QuorumProposalWrapper<TYPES> {
1233 fn view_number(&self) -> TYPES::View {
1234 self.proposal.view_number
1235 }
1236}
1237
1238impl<TYPES: NodeType> HasViewNumber<TYPES> for QuorumProposalWrapperLegacy<TYPES> {
1239 fn view_number(&self) -> TYPES::View {
1240 self.proposal.view_number
1241 }
1242}
1243
1244impl<TYPES: NodeType> HasViewNumber<TYPES> for UpgradeProposal<TYPES> {
1245 fn view_number(&self) -> TYPES::View {
1246 self.view_number
1247 }
1248}
1249
1250impl_has_epoch!(
1251 QuorumProposal2<TYPES>,
1252 DaProposal2<TYPES>,
1253 QuorumProposal2Legacy<TYPES>
1254);
1255
1256impl_has_none_epoch!(
1257 QuorumProposal<TYPES>,
1258 DaProposal<TYPES>,
1259 UpgradeProposal<TYPES>
1260);
1261
1262impl<TYPES: NodeType> HasEpoch<TYPES> for QuorumProposalWrapper<TYPES> {
1263 #[allow(clippy::panic)]
1265 fn epoch(&self) -> Option<TYPES::Epoch> {
1266 self.proposal.epoch()
1267 }
1268}
1269
1270impl<TYPES: NodeType> HasEpoch<TYPES> for QuorumProposalWrapperLegacy<TYPES> {
1271 #[allow(clippy::panic)]
1273 fn epoch(&self) -> Option<TYPES::Epoch> {
1274 self.proposal.epoch()
1275 }
1276}
1277
1278#[derive(Error, Debug, Serialize, Deserialize)]
1280pub enum BlockError {
1281 #[error("Invalid block header: {0}")]
1283 InvalidBlockHeader(String),
1284
1285 #[error("Inconsistent payload commitment")]
1287 InconsistentPayloadCommitment,
1288
1289 #[error("Failed to apply block header: {0}")]
1291 FailedHeaderApply(String),
1292}
1293
1294pub trait TestableLeaf {
1296 type NodeType: NodeType;
1298
1299 fn create_random_transaction(
1301 &self,
1302 rng: &mut dyn rand::RngCore,
1303 padding: u64,
1304 ) -> <<Self::NodeType as NodeType>::BlockPayload as BlockPayload<Self::NodeType>>::Transaction;
1305}
1306
1307#[derive(Serialize, Deserialize, Clone, Debug, Eq)]
1311#[serde(bound(deserialize = ""))]
1312pub struct Leaf<TYPES: NodeType> {
1313 view_number: TYPES::View,
1315
1316 justify_qc: QuorumCertificate<TYPES>,
1318
1319 parent_commitment: Commitment<Self>,
1322
1323 block_header: TYPES::BlockHeader,
1325
1326 upgrade_certificate: Option<UpgradeCertificate<TYPES>>,
1328
1329 block_payload: Option<TYPES::BlockPayload>,
1333}
1334
1335#[derive(Serialize, Deserialize, Clone, Debug, Eq)]
1338#[serde(bound(deserialize = ""))]
1339pub struct Leaf2<TYPES: NodeType> {
1340 view_number: TYPES::View,
1342
1343 justify_qc: QuorumCertificate2<TYPES>,
1345
1346 next_epoch_justify_qc: Option<NextEpochQuorumCertificate2<TYPES>>,
1348
1349 parent_commitment: Commitment<Self>,
1352
1353 block_header: TYPES::BlockHeader,
1355
1356 upgrade_certificate: Option<UpgradeCertificate<TYPES>>,
1358
1359 block_payload: Option<TYPES::BlockPayload>,
1363
1364 pub view_change_evidence: Option<ViewChangeEvidence2<TYPES>>,
1366
1367 #[serde(with = "serde_bytes")]
1372 pub next_drb_result: Option<DrbResult>,
1373
1374 pub with_epoch: bool,
1376}
1377
1378impl<TYPES: NodeType> Leaf2<TYPES> {
1379 #[must_use]
1386 pub async fn genesis<V: Versions>(
1387 validated_state: &TYPES::ValidatedState,
1388 instance_state: &TYPES::InstanceState,
1389 ) -> Self {
1390 let epoch = genesis_epoch_from_version::<V, TYPES>();
1391
1392 let (payload, metadata) =
1393 TYPES::BlockPayload::from_transactions([], validated_state, instance_state)
1394 .await
1395 .unwrap();
1396
1397 let genesis_view = TYPES::View::genesis();
1398
1399 let block_header =
1400 TYPES::BlockHeader::genesis::<V>(instance_state, payload.clone(), &metadata);
1401
1402 let block_number = if V::Base::VERSION < V::Epochs::VERSION {
1403 None
1404 } else {
1405 Some(0u64)
1406 };
1407
1408 let null_quorum_data = QuorumData2 {
1409 leaf_commit: Commitment::<Leaf2<TYPES>>::default_commitment_no_preimage(),
1410 epoch,
1411 block_number,
1412 };
1413
1414 let justify_qc = QuorumCertificate2::new(
1415 null_quorum_data.clone(),
1416 null_quorum_data.commit(),
1417 genesis_view,
1418 None,
1419 PhantomData,
1420 );
1421
1422 Self {
1423 view_number: genesis_view,
1424 justify_qc,
1425 next_epoch_justify_qc: None,
1426 parent_commitment: null_quorum_data.leaf_commit,
1427 upgrade_certificate: None,
1428 block_header: block_header.clone(),
1429 block_payload: Some(payload),
1430 view_change_evidence: None,
1431 next_drb_result: None,
1432 with_epoch: epoch.is_some(),
1433 }
1434 }
1435 pub fn view_number(&self) -> TYPES::View {
1437 self.view_number
1438 }
1439 pub fn epoch(&self, epoch_height: u64) -> Option<TYPES::Epoch> {
1441 option_epoch_from_block_number::<TYPES>(
1442 self.with_epoch,
1443 self.block_header.block_number(),
1444 epoch_height,
1445 )
1446 }
1447 pub fn height(&self) -> u64 {
1451 self.block_header.block_number()
1452 }
1453 pub fn justify_qc(&self) -> QuorumCertificate2<TYPES> {
1455 self.justify_qc.clone()
1456 }
1457 pub fn next_epoch_justify_qc(&self) -> Option<NextEpochQuorumCertificate2<TYPES>> {
1461 self.next_epoch_justify_qc.clone()
1462 }
1463 pub fn upgrade_certificate(&self) -> Option<UpgradeCertificate<TYPES>> {
1465 self.upgrade_certificate.clone()
1466 }
1467 pub fn parent_commitment(&self) -> Commitment<Self> {
1469 self.parent_commitment
1470 }
1471 pub fn block_header(&self) -> &<TYPES as NodeType>::BlockHeader {
1473 &self.block_header
1474 }
1475
1476 pub fn block_header_mut(&mut self) -> &mut <TYPES as NodeType>::BlockHeader {
1478 &mut self.block_header
1479 }
1480 pub fn fill_block_payload<V: Versions>(
1487 &mut self,
1488 block_payload: TYPES::BlockPayload,
1489 num_storage_nodes: usize,
1490 version: Version,
1491 ) -> std::result::Result<(), BlockError> {
1492 let encoded_txns = block_payload.encode();
1493 let commitment = vid_commitment::<V>(
1494 &encoded_txns,
1495 &self.block_header.metadata().encode(),
1496 num_storage_nodes,
1497 version,
1498 );
1499 if commitment != self.block_header.payload_commitment() {
1500 return Err(BlockError::InconsistentPayloadCommitment);
1501 }
1502 self.block_payload = Some(block_payload);
1503 Ok(())
1504 }
1505
1506 pub fn unfill_block_payload(&mut self) -> Option<TYPES::BlockPayload> {
1508 self.block_payload.take()
1509 }
1510
1511 pub fn fill_block_payload_unchecked(&mut self, block_payload: TYPES::BlockPayload) {
1514 self.block_payload = Some(block_payload);
1515 }
1516
1517 pub fn block_payload(&self) -> Option<TYPES::BlockPayload> {
1519 self.block_payload.clone()
1520 }
1521
1522 pub fn payload_commitment(&self) -> VidCommitment {
1524 self.block_header().payload_commitment()
1525 }
1526
1527 pub async fn extends_upgrade(
1535 &self,
1536 parent: &Self,
1537 decided_upgrade_certificate: &Arc<RwLock<Option<UpgradeCertificate<TYPES>>>>,
1538 ) -> Result<()> {
1539 match (self.upgrade_certificate(), parent.upgrade_certificate()) {
1540 (None | Some(_), None) => {},
1544 (None, Some(parent_cert)) => {
1548 let decided_upgrade_certificate_read = decided_upgrade_certificate.read().await;
1549 ensure!(
1550 self.view_number() > parent_cert.data.new_version_first_view
1551 || (self.view_number() > parent_cert.data.decide_by
1552 && decided_upgrade_certificate_read.is_none()),
1553 "The new leaf is missing an upgrade certificate that was present in its \
1554 parent, and should still be live."
1555 );
1556 },
1557 (Some(cert), Some(parent_cert)) => {
1561 ensure!(
1562 cert == parent_cert,
1563 "The new leaf does not extend the parent leaf, because it has attached a \
1564 different upgrade certificate."
1565 );
1566 },
1567 }
1568
1569 Ok(())
1573 }
1574
1575 pub fn to_leaf_unsafe(self) -> Leaf<TYPES> {
1577 let bytes: [u8; 32] = self.parent_commitment.into();
1578
1579 Leaf {
1580 view_number: self.view_number,
1581 justify_qc: self.justify_qc.to_qc(),
1582 parent_commitment: Commitment::from_raw(bytes),
1583 block_header: self.block_header,
1584 upgrade_certificate: self.upgrade_certificate,
1585 block_payload: self.block_payload,
1586 }
1587 }
1588}
1589
1590impl<TYPES: NodeType> Committable for Leaf2<TYPES> {
1591 fn commit(&self) -> committable::Commitment<Self> {
1592 let Leaf2 {
1593 view_number,
1594 justify_qc,
1595 next_epoch_justify_qc,
1596 parent_commitment,
1597 block_header,
1598 upgrade_certificate,
1599 block_payload: _,
1600 view_change_evidence,
1601 next_drb_result,
1602 with_epoch,
1603 } = self;
1604
1605 let mut cb = RawCommitmentBuilder::new("leaf commitment")
1606 .u64_field("view number", **view_number)
1607 .field("parent leaf commitment", *parent_commitment)
1608 .field("block header", block_header.commit())
1609 .field("justify qc", justify_qc.commit())
1610 .optional("upgrade certificate", upgrade_certificate);
1611
1612 if *with_epoch {
1613 cb = cb
1614 .constant_str("with_epoch")
1615 .optional("next_epoch_justify_qc", next_epoch_justify_qc);
1616
1617 if let Some(next_drb_result) = next_drb_result {
1618 cb = cb
1619 .constant_str("next_drb_result")
1620 .fixed_size_bytes(next_drb_result);
1621 }
1622
1623 match view_change_evidence {
1624 Some(ViewChangeEvidence2::Timeout(cert)) => {
1625 cb = cb.field("timeout cert", cert.commit());
1626 },
1627 Some(ViewChangeEvidence2::ViewSync(cert)) => {
1628 cb = cb.field("viewsync cert", cert.commit());
1629 },
1630 None => {},
1631 }
1632 }
1633
1634 cb.finalize()
1635 }
1636}
1637
1638impl<TYPES: NodeType> Leaf<TYPES> {
1639 #[allow(clippy::unused_async)]
1640 pub async fn commit<V: Versions>(
1643 &self,
1644 _upgrade_lock: &UpgradeLock<TYPES, V>,
1645 ) -> Commitment<Self> {
1646 <Self as Committable>::commit(self)
1647 }
1648}
1649
1650impl<TYPES: NodeType> PartialEq for Leaf<TYPES> {
1651 fn eq(&self, other: &Self) -> bool {
1652 self.view_number == other.view_number
1653 && self.justify_qc == other.justify_qc
1654 && self.parent_commitment == other.parent_commitment
1655 && self.block_header == other.block_header
1656 }
1657}
1658
1659impl<TYPES: NodeType> PartialEq for Leaf2<TYPES> {
1660 fn eq(&self, other: &Self) -> bool {
1661 let Leaf2 {
1662 view_number,
1663 justify_qc,
1664 next_epoch_justify_qc,
1665 parent_commitment,
1666 block_header,
1667 upgrade_certificate,
1668 block_payload: _,
1669 view_change_evidence,
1670 next_drb_result,
1671 with_epoch,
1672 } = self;
1673
1674 *view_number == other.view_number
1675 && *justify_qc == other.justify_qc
1676 && *next_epoch_justify_qc == other.next_epoch_justify_qc
1677 && *parent_commitment == other.parent_commitment
1678 && *block_header == other.block_header
1679 && *upgrade_certificate == other.upgrade_certificate
1680 && *view_change_evidence == other.view_change_evidence
1681 && *next_drb_result == other.next_drb_result
1682 && *with_epoch == other.with_epoch
1683 }
1684}
1685
1686impl<TYPES: NodeType> Hash for Leaf<TYPES> {
1687 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
1688 self.view_number.hash(state);
1689 self.justify_qc.hash(state);
1690 self.parent_commitment.hash(state);
1691 self.block_header.hash(state);
1692 }
1693}
1694
1695impl<TYPES: NodeType> Hash for Leaf2<TYPES> {
1696 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
1697 self.commit().hash(state);
1698 self.view_number.hash(state);
1699 self.justify_qc.hash(state);
1700 self.parent_commitment.hash(state);
1701 self.block_header.hash(state);
1702 }
1703}
1704
1705impl<TYPES: NodeType> Display for Leaf<TYPES> {
1706 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1707 write!(
1708 f,
1709 "view: {:?}, height: {:?}, justify: {}",
1710 self.view_number,
1711 self.height(),
1712 self.justify_qc
1713 )
1714 }
1715}
1716
1717impl<TYPES: NodeType> QuorumCertificate<TYPES> {
1718 #[must_use]
1719 pub async fn genesis<V: Versions>(
1721 validated_state: &TYPES::ValidatedState,
1722 instance_state: &TYPES::InstanceState,
1723 ) -> Self {
1724 let upgrade_lock = UpgradeLock::<TYPES, V>::new();
1726
1727 let genesis_view = <TYPES::View as ConsensusTime>::genesis();
1728
1729 let data = QuorumData {
1730 leaf_commit: Leaf::genesis::<V>(validated_state, instance_state)
1731 .await
1732 .commit(&upgrade_lock)
1733 .await,
1734 };
1735
1736 let versioned_data =
1737 VersionedVoteData::<_, _, V>::new_infallible(data.clone(), genesis_view, &upgrade_lock)
1738 .await;
1739
1740 let bytes: [u8; 32] = versioned_data.commit().into();
1741
1742 Self::new(
1743 data,
1744 Commitment::from_raw(bytes),
1745 genesis_view,
1746 None,
1747 PhantomData,
1748 )
1749 }
1750}
1751
1752impl<TYPES: NodeType> QuorumCertificate2<TYPES> {
1753 #[must_use]
1754 pub async fn genesis<V: Versions>(
1756 validated_state: &TYPES::ValidatedState,
1757 instance_state: &TYPES::InstanceState,
1758 ) -> Self {
1759 let upgrade_lock = UpgradeLock::<TYPES, V>::new();
1761
1762 let genesis_view = <TYPES::View as ConsensusTime>::genesis();
1763
1764 let genesis_leaf = Leaf2::genesis::<V>(validated_state, instance_state).await;
1765 let block_number = if upgrade_lock.epochs_enabled(genesis_view).await {
1766 Some(genesis_leaf.height())
1767 } else {
1768 None
1769 };
1770 let data = QuorumData2 {
1771 leaf_commit: genesis_leaf.commit(),
1772 epoch: genesis_epoch_from_version::<V, TYPES>(), block_number,
1774 };
1775
1776 let versioned_data =
1777 VersionedVoteData::<_, _, V>::new_infallible(data.clone(), genesis_view, &upgrade_lock)
1778 .await;
1779
1780 let bytes: [u8; 32] = versioned_data.commit().into();
1781
1782 Self::new(
1783 data,
1784 Commitment::from_raw(bytes),
1785 genesis_view,
1786 None,
1787 PhantomData,
1788 )
1789 }
1790}
1791
1792impl<TYPES: NodeType> Leaf<TYPES> {
1793 #[must_use]
1800 pub async fn genesis<V: Versions>(
1801 validated_state: &TYPES::ValidatedState,
1802 instance_state: &TYPES::InstanceState,
1803 ) -> Self {
1804 let (payload, metadata) =
1805 TYPES::BlockPayload::from_transactions([], validated_state, instance_state)
1806 .await
1807 .unwrap();
1808
1809 let genesis_view = TYPES::View::genesis();
1810
1811 let block_header =
1812 TYPES::BlockHeader::genesis::<V>(instance_state, payload.clone(), &metadata);
1813
1814 let null_quorum_data = QuorumData {
1815 leaf_commit: Commitment::<Leaf<TYPES>>::default_commitment_no_preimage(),
1816 };
1817
1818 let justify_qc = QuorumCertificate::new(
1819 null_quorum_data.clone(),
1820 null_quorum_data.commit(),
1821 genesis_view,
1822 None,
1823 PhantomData,
1824 );
1825
1826 Self {
1827 view_number: genesis_view,
1828 justify_qc,
1829 parent_commitment: null_quorum_data.leaf_commit,
1830 upgrade_certificate: None,
1831 block_header: block_header.clone(),
1832 block_payload: Some(payload),
1833 }
1834 }
1835
1836 pub fn view_number(&self) -> TYPES::View {
1838 self.view_number
1839 }
1840 pub fn height(&self) -> u64 {
1844 self.block_header.block_number()
1845 }
1846 pub fn justify_qc(&self) -> QuorumCertificate<TYPES> {
1848 self.justify_qc.clone()
1849 }
1850 pub fn upgrade_certificate(&self) -> Option<UpgradeCertificate<TYPES>> {
1852 self.upgrade_certificate.clone()
1853 }
1854 pub fn parent_commitment(&self) -> Commitment<Self> {
1856 self.parent_commitment
1857 }
1858 pub fn block_header(&self) -> &<TYPES as NodeType>::BlockHeader {
1860 &self.block_header
1861 }
1862
1863 pub fn block_header_mut(&mut self) -> &mut <TYPES as NodeType>::BlockHeader {
1865 &mut self.block_header
1866 }
1867 pub fn fill_block_payload<V: Versions>(
1874 &mut self,
1875 block_payload: TYPES::BlockPayload,
1876 num_storage_nodes: usize,
1877 version: Version,
1878 ) -> std::result::Result<(), BlockError> {
1879 let encoded_txns = block_payload.encode();
1880 let commitment = vid_commitment::<V>(
1881 &encoded_txns,
1882 &self.block_header.metadata().encode(),
1883 num_storage_nodes,
1884 version,
1885 );
1886 if commitment != self.block_header.payload_commitment() {
1887 return Err(BlockError::InconsistentPayloadCommitment);
1888 }
1889 self.block_payload = Some(block_payload);
1890 Ok(())
1891 }
1892
1893 pub fn unfill_block_payload(&mut self) -> Option<TYPES::BlockPayload> {
1895 self.block_payload.take()
1896 }
1897
1898 pub fn fill_block_payload_unchecked(&mut self, block_payload: TYPES::BlockPayload) {
1901 self.block_payload = Some(block_payload);
1902 }
1903
1904 pub fn block_payload(&self) -> Option<TYPES::BlockPayload> {
1906 self.block_payload.clone()
1907 }
1908
1909 pub fn payload_commitment(&self) -> VidCommitment {
1911 self.block_header().payload_commitment()
1912 }
1913
1914 pub async fn extends_upgrade(
1922 &self,
1923 parent: &Self,
1924 decided_upgrade_certificate: &Arc<RwLock<Option<UpgradeCertificate<TYPES>>>>,
1925 ) -> Result<()> {
1926 match (self.upgrade_certificate(), parent.upgrade_certificate()) {
1927 (None | Some(_), None) => {},
1931 (None, Some(parent_cert)) => {
1935 let decided_upgrade_certificate_read = decided_upgrade_certificate.read().await;
1936 ensure!(
1937 self.view_number() > parent_cert.data.new_version_first_view
1938 || (self.view_number() > parent_cert.data.decide_by
1939 && decided_upgrade_certificate_read.is_none()),
1940 "The new leaf is missing an upgrade certificate that was present in its \
1941 parent, and should still be live."
1942 );
1943 },
1944 (Some(cert), Some(parent_cert)) => {
1948 ensure!(
1949 cert == parent_cert,
1950 "The new leaf does not extend the parent leaf, because it has attached a \
1951 different upgrade certificate."
1952 );
1953 },
1954 }
1955
1956 Ok(())
1960 }
1961}
1962
1963impl<TYPES: NodeType> TestableLeaf for Leaf<TYPES>
1964where
1965 TYPES::ValidatedState: TestableState<TYPES>,
1966 TYPES::BlockPayload: TestableBlock<TYPES>,
1967{
1968 type NodeType = TYPES;
1969
1970 fn create_random_transaction(
1971 &self,
1972 rng: &mut dyn rand::RngCore,
1973 padding: u64,
1974 ) -> <<Self::NodeType as NodeType>::BlockPayload as BlockPayload<Self::NodeType>>::Transaction
1975 {
1976 TYPES::ValidatedState::create_random_transaction(None, rng, padding)
1977 }
1978}
1979impl<TYPES: NodeType> TestableLeaf for Leaf2<TYPES>
1980where
1981 TYPES::ValidatedState: TestableState<TYPES>,
1982 TYPES::BlockPayload: TestableBlock<TYPES>,
1983{
1984 type NodeType = TYPES;
1985
1986 fn create_random_transaction(
1987 &self,
1988 rng: &mut dyn rand::RngCore,
1989 padding: u64,
1990 ) -> <<Self::NodeType as NodeType>::BlockPayload as BlockPayload<Self::NodeType>>::Transaction
1991 {
1992 TYPES::ValidatedState::create_random_transaction(None, rng, padding)
1993 }
1994}
1995#[must_use]
1997pub fn fake_commitment<S: Committable>() -> Commitment<S> {
1998 RawCommitmentBuilder::new("Dummy commitment for arbitrary genesis").finalize()
1999}
2000
2001#[must_use]
2003pub fn random_commitment<S: Committable>(rng: &mut dyn rand::RngCore) -> Commitment<S> {
2004 let random_array: Vec<u8> = (0u8..100u8).map(|_| rng.gen_range(0..255)).collect();
2005 RawCommitmentBuilder::new("Random Commitment")
2006 .constant_str("Random Field")
2007 .var_size_bytes(&random_array)
2008 .finalize()
2009}
2010
2011pub fn serialize_signature2<TYPES: NodeType>(
2015 signatures: &<TYPES::SignatureKey as SignatureKey>::QcType,
2016) -> Vec<u8> {
2017 let mut signatures_bytes = vec![];
2018 signatures_bytes.extend("Yes".as_bytes());
2019
2020 let (sig, proof) = TYPES::SignatureKey::sig_proof(signatures);
2021 let proof_bytes = bincode_opts()
2022 .serialize(&proof.as_bitslice())
2023 .expect("This serialization shouldn't be able to fail");
2024 signatures_bytes.extend("bitvec proof".as_bytes());
2025 signatures_bytes.extend(proof_bytes.as_slice());
2026 let sig_bytes = bincode_opts()
2027 .serialize(&sig)
2028 .expect("This serialization shouldn't be able to fail");
2029 signatures_bytes.extend("aggregated signature".as_bytes());
2030 signatures_bytes.extend(sig_bytes.as_slice());
2031 signatures_bytes
2032}
2033
2034impl<TYPES: NodeType> Committable for Leaf<TYPES> {
2035 fn commit(&self) -> committable::Commitment<Self> {
2036 RawCommitmentBuilder::new("leaf commitment")
2037 .u64_field("view number", *self.view_number)
2038 .field("parent leaf commitment", self.parent_commitment)
2039 .field("block header", self.block_header.commit())
2040 .field("justify qc", self.justify_qc.commit())
2041 .optional("upgrade certificate", &self.upgrade_certificate)
2042 .finalize()
2043 }
2044}
2045
2046impl<TYPES: NodeType> Leaf2<TYPES> {
2047 pub fn from_quorum_proposal(quorum_proposal: &QuorumProposalWrapper<TYPES>) -> Self {
2049 let QuorumProposalWrapper {
2052 proposal:
2053 QuorumProposal2 {
2054 view_number,
2055 epoch,
2056 justify_qc,
2057 next_epoch_justify_qc,
2058 block_header,
2059 upgrade_certificate,
2060 view_change_evidence,
2061 next_drb_result,
2062 state_cert: _,
2063 },
2064 } = quorum_proposal;
2065
2066 Self {
2067 view_number: *view_number,
2068 justify_qc: justify_qc.clone(),
2069 next_epoch_justify_qc: next_epoch_justify_qc.clone(),
2070 parent_commitment: justify_qc.data().leaf_commit,
2071 block_header: block_header.clone(),
2072 upgrade_certificate: upgrade_certificate.clone(),
2073 block_payload: None,
2074 view_change_evidence: view_change_evidence.clone(),
2075 next_drb_result: *next_drb_result,
2076 with_epoch: epoch.is_some(),
2077 }
2078 }
2079}
2080
2081impl<TYPES: NodeType> Leaf<TYPES> {
2082 pub fn from_quorum_proposal(quorum_proposal: &QuorumProposal<TYPES>) -> Self {
2084 let QuorumProposal {
2087 view_number,
2088 justify_qc,
2089 block_header,
2090 upgrade_certificate,
2091 proposal_certificate: _,
2092 } = quorum_proposal;
2093
2094 Self {
2095 view_number: *view_number,
2096 justify_qc: justify_qc.clone(),
2097 parent_commitment: justify_qc.data().leaf_commit,
2098 block_header: block_header.clone(),
2099 upgrade_certificate: upgrade_certificate.clone(),
2100 block_payload: None,
2101 }
2102 }
2103}
2104
2105pub mod null_block {
2106 #![allow(missing_docs)]
2107
2108 use jf_advz::VidScheme;
2109 use vbs::version::StaticVersionType;
2110
2111 use crate::{
2112 data::VidCommitment,
2113 traits::{
2114 block_contents::BuilderFee,
2115 node_implementation::{NodeType, Versions},
2116 signature_key::BuilderSignatureKey,
2117 BlockPayload,
2118 },
2119 vid::advz::advz_scheme,
2120 };
2121
2122 #[must_use]
2131 pub fn commitment<V: Versions>(num_storage_nodes: usize) -> Option<VidCommitment> {
2132 let vid_result = advz_scheme(num_storage_nodes).commit_only(Vec::new());
2133
2134 match vid_result {
2135 Ok(r) => Some(VidCommitment::V0(r)),
2136 Err(_) => None,
2137 }
2138 }
2139
2140 #[must_use]
2142 pub fn builder_fee<TYPES: NodeType, V: Versions>(
2143 num_storage_nodes: usize,
2144 version: vbs::version::Version,
2145 ) -> Option<BuilderFee<TYPES>> {
2146 const FEE_AMOUNT: u64 = 0;
2148
2149 let (pub_key, priv_key) =
2150 <TYPES::BuilderSignatureKey as BuilderSignatureKey>::generated_from_seed_indexed(
2151 [0_u8; 32], 0,
2152 );
2153
2154 if version >= V::Epochs::VERSION {
2155 let (_null_block, null_block_metadata) =
2156 <TYPES::BlockPayload as BlockPayload<TYPES>>::empty();
2157
2158 match TYPES::BuilderSignatureKey::sign_fee(&priv_key, FEE_AMOUNT, &null_block_metadata)
2159 {
2160 Ok(sig) => Some(BuilderFee {
2161 fee_amount: FEE_AMOUNT,
2162 fee_account: pub_key,
2163 fee_signature: sig,
2164 }),
2165 Err(_) => None,
2166 }
2167 } else {
2168 let (_null_block, null_block_metadata) =
2169 <TYPES::BlockPayload as BlockPayload<TYPES>>::empty();
2170
2171 match TYPES::BuilderSignatureKey::sign_fee_with_vid_commitment(
2172 &priv_key,
2173 FEE_AMOUNT,
2174 &null_block_metadata,
2175 &commitment::<V>(num_storage_nodes)?,
2176 ) {
2177 Ok(sig) => Some(BuilderFee {
2178 fee_amount: FEE_AMOUNT,
2179 fee_account: pub_key,
2180 fee_signature: sig,
2181 }),
2182 Err(_) => None,
2183 }
2184 }
2185 }
2186}
2187
2188#[derive(Debug, Eq, PartialEq, Clone)]
2190pub struct PackedBundle<TYPES: NodeType> {
2191 pub encoded_transactions: Arc<[u8]>,
2193
2194 pub metadata: <TYPES::BlockPayload as BlockPayload<TYPES>>::Metadata,
2196
2197 pub view_number: TYPES::View,
2199
2200 pub epoch_number: Option<TYPES::Epoch>,
2202
2203 pub sequencing_fees: Vec1<BuilderFee<TYPES>>,
2205}
2206
2207impl<TYPES: NodeType> PackedBundle<TYPES> {
2208 pub fn new(
2210 encoded_transactions: Arc<[u8]>,
2211 metadata: <TYPES::BlockPayload as BlockPayload<TYPES>>::Metadata,
2212 view_number: TYPES::View,
2213 epoch_number: Option<TYPES::Epoch>,
2214 sequencing_fees: Vec1<BuilderFee<TYPES>>,
2215 ) -> Self {
2216 Self {
2217 encoded_transactions,
2218 metadata,
2219 view_number,
2220 epoch_number,
2221 sequencing_fees,
2222 }
2223 }
2224}
2225
2226#[cfg(test)]
2227mod test {
2228 use super::*;
2229
2230 #[test]
2231 fn test_vid_commitment_display() {
2232 let vc = VidCommitment::V0(VidCommitment0::default());
2233 assert_eq!(
2234 format!("{vc}"),
2235 "HASH~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAI"
2236 );
2237 assert_eq!(
2238 format!("{vc:?}"),
2239 "HASH~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAI"
2240 );
2241
2242 let vc = VidCommitment::V1(VidCommitment1::default());
2243 assert_eq!(
2244 format!("{vc}"),
2245 "AvidMCommit~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADr"
2246 );
2247 assert_eq!(
2248 format!("{vc:?}"),
2249 "AvidMCommit~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADr"
2250 );
2251
2252 let vc = VidCommitment::V2(VidCommitment2::default());
2253 assert_eq!(
2254 format!("{vc}"),
2255 "AvidmGf2Commit~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACq"
2256 );
2257 assert_eq!(
2258 format!("{vc:?}"),
2259 "AvidmGf2Commit~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACq"
2260 );
2261 }
2262}